├── .editorconfig ├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── core.d.ts ├── core.js ├── gulpfile.js ├── http-status-codes.d.ts ├── http-status-codes.js ├── in-memory-backend.service.d.ts ├── in-memory-backend.service.js ├── package.json ├── src ├── core.ts ├── http-status-codes.ts └── in-memory-backend.service.ts ├── tsconfig.json ├── tslint.json ├── typings.json └── web-api.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | # Indentation override 18 | #[lib/**.js] 19 | #[{package.json,.travis.yml}] 20 | #[**/**.js] 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | a2-in-memory-web-api 2 | node_modules 3 | typings 4 | **/*.js.map 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | a2-in-memory-web-api 2 | gulpfile.js 3 | .gitignore 4 | .npmignore 5 | tsconfig.json -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.1.17 (2016-04-29) 3 | * update packages 4 | * Angular 2 beta 17 5 | * RxJs 5.0.0-beta.6 6 | 7 | 8 | # 0.1.16 (2016-04-25) 9 | * update packages 10 | * Angular 2 beta 16 11 | * zone.js 0.6.12 12 | 13 | 14 | # 0.1.15 (2016-04-13) 15 | * update packages 16 | * Angular 2 beta 15 17 | * zone.js 0.6.10 18 | 19 | 20 | # 0.1.14 (2016-04-07) 21 | * update packages 22 | * Angular 2 beta 14 23 | * systemjs v.0.19.25 24 | * typings v.0.7.11 25 | * Add tslint and editorconfig 26 | 27 | 28 | # 0.1.13 (2016-03-31) 29 | * update packages 30 | * Angular 2 beta 13 31 | * systemjs v.0.19.25 32 | * typings v.0.7.11 33 | 34 | 35 | # 0.1.12 (2016-03-23) 36 | * update packages 37 | * Angular 2 beta 12 38 | 39 | 40 | # 0.1.11 (2016-03-18) 41 | * update packages 42 | * Angular 2 beta 11 43 | 44 | 45 | # 0.1.10 (2016-03-17) [DO NOT USE] 46 | **Can't compile cleanly due to zone.d.ts problem** 47 | 48 | * update packages 49 | * Angular 2 beta 10 50 | * es6-shim: "0.35.0 51 | * zone.js: 0.6.4 52 | * removed typings files from source control 53 | * update es6-shim typings to commit 7de6c3 54 | 55 | 56 | 57 | # 0.1.9 (2016-03-09) 58 | * update packages 59 | * Angular 2 beta 9 60 | * Typings to 0.7.5 (clear your typings folder!) 61 | 62 | 63 | # 0.1.8 (2016-03-03) 64 | * update packages 65 | * Angular 2 beta 8 66 | 67 | 68 | # 0.1.7 (2016-02-20) 69 | * **REMOVE npm postinstall .. STOP ADDING IT** 70 | 71 | 72 | # 0.1.6 (2016-02-20) 73 | * update packages 74 | * Angular 2 beta 7, 75 | * "reflect-metadata": "0.1.2", 76 | * "rxjs": "5.0.0-beta.2", 77 | * "zone.js": "0.5.15" 78 | * npm postinstall automatically runs typings 79 | 80 | 81 | # 0.1.5 (2016-02-11) 82 | * remove `npm postinstall` script 83 | 84 | 85 | # 0.1.4 (2016-02-11) 86 | * update to Angular 2 beta 6 (skip 4-5) 87 | 88 | 89 | # 0.1.3 (2016-02-11) 90 | * update to Angular 2 beta 6 RC (skip 4-5) 91 | [DO NOT USE] 92 | 93 | 94 | # 0.1.2 (2016-02-03) 95 | * update to Angular 2 beta 3 96 | 97 | 98 | # 0.1.1 (2016-02-02) 99 | * update to Angular 2 beta 2 100 | * exclude tsconfig.json from the npm package 101 | 102 | 103 | # 0.1.0 (2016-01-19) 104 | 105 | ### Bug Fixes 106 | 107 | * exclude .npmignore from the npm package 108 | 109 | ### Features 110 | 111 | * Added this CHANGELOG.md 112 | * Reversed import order in core so that the real code is at the top and status codes at the bottom 113 | * Output file renamed "web-api.js" 114 | 115 | ### BREAKING CHANGES 116 | 117 | * Output file renamed from "dev.js" to "web-api.js" 118 | 119 | 120 | # 0.0.4 (2016-01-18) 121 | 122 | First draft 123 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ward Bell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular2-in-memory-web-api (DEPRECATED) 2 | 3 | **Deprecated in favor of the angular repo: https://github.com/angular/in-memory-web-api** 4 | 5 | **Way out of date and no longer maintained** 6 | 7 | An in-memory web api for Angular 2 demos and tests. 8 | 9 | See usage in the Angular.io 10 | [Server Communication](https://angular.io/docs/ts/latest/guide/server-communication.html) chapter. 11 | 12 | # To Do 13 | * add documentation 14 | * add tests (shameful omission!) 15 | 16 | # Build Instructions 17 | 18 | Mostly gulp driven. 19 | 20 | The following describes steps for updating from one Angular version to the next 21 | 22 | >This is essential even when there are no changes of real consequence. 23 | Neglecting to synchronize Angular 2 versions 24 | triggers typescript definition duplication error messages when 25 | compiling your application project. 26 | 27 | - `gulp bump` - up the package version number 28 | 29 | - update `CHANGELOG.MD` to record the change 30 | 31 | - update the dependent version(s) in `package.json` 32 | 33 | - `npm install` the new package(s) (make sure they really do install!)
34 | `npm list --depth=0` 35 | 36 | - consider updating typings, install individually or together: 37 | `npm run typings -- install packagename1 packagename2 --ambient --save` 38 | 39 | **NB: Do not add to `npm postinstall` as that screws up consumers!** 40 | 41 | - `npm run tsc` to confirm the project compiles w/o error (sanity check) 42 | 43 | -- NO TESTS YET ... BAD -- 44 | 45 | - `gulp build` 46 | - commit and push 47 | 48 | - `npm publish` 49 | 50 | - Fix and validate angular.io docs samples 51 | 52 | - Add two tags to the release commit with for npmcdn 53 | - the version number 54 | - 'latest' 55 | -------------------------------------------------------------------------------- /core.d.ts: -------------------------------------------------------------------------------- 1 | export * from './in-memory-backend.service'; 2 | export * from './http-status-codes'; 3 | -------------------------------------------------------------------------------- /core.js: -------------------------------------------------------------------------------- 1 | System.register(['./in-memory-backend.service', './http-status-codes'], function(exports_1, context_1) { 2 | "use strict"; 3 | var __moduleName = context_1 && context_1.id; 4 | function exportStar_1(m) { 5 | var exports = {}; 6 | for(var n in m) { 7 | if (n !== "default") exports[n] = m[n]; 8 | } 9 | exports_1(exports); 10 | } 11 | return { 12 | setters:[ 13 | function (in_memory_backend_service_1_1) { 14 | exportStar_1(in_memory_backend_service_1_1); 15 | }, 16 | function (http_status_codes_1_1) { 17 | exportStar_1(http_status_codes_1_1); 18 | }], 19 | execute: function() { 20 | } 21 | } 22 | }); 23 | //# sourceMappingURL=core.js.map -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var $ = require('gulp-load-plugins')({lazy: true}); 3 | var args = require('yargs').argv; 4 | var cp = require('child_process'); 5 | var del = require('del'); 6 | 7 | var path = require("path"); 8 | var Builder = require('systemjs-builder'); 9 | 10 | var tsOutput = './a2-in-memory-web-api/'; 11 | var jsCopySrc = [tsOutput+'*.js', tsOutput+'*.d.ts'] 12 | 13 | gulp.task('default', ['help']); 14 | 15 | gulp.task('help', $.taskListing.withFilters(function (taskName) { 16 | var isSubTask = taskName.substr(0, 1) == "_"; 17 | return isSubTask; 18 | }, function (taskName) { 19 | var shouldRemove = taskName === 'default'; 20 | return shouldRemove; 21 | })); 22 | 23 | gulp.task('build', ['tsc'], build); 24 | 25 | gulp.task('build-only', build); 26 | 27 | gulp.task('tsc', ['tsc-only'], function(){ 28 | return gulp 29 | .src(jsCopySrc) 30 | .pipe(gulp.dest('./')); 31 | }); 32 | 33 | gulp.task('tsc-only',['clean'], function(done) { 34 | runTSC('./', done); 35 | }); 36 | 37 | gulp.task('clean', function(done) { 38 | clean([tsOutput+'*.*', '*.js','*.d.ts','!gulpfile.js'], done); 39 | }); 40 | 41 | /** 42 | * Bump the version 43 | * --type=pre will bump the prerelease version *.*.*-x 44 | * --type=patch or no flag will bump the patch version *.*.x 45 | * --type=minor will bump the minor version *.x.* 46 | * --type=major will bump the major version x.*.* 47 | * --version=1.2.3 will bump to a specific version and ignore other flags 48 | */ 49 | gulp.task('bump', function() { 50 | var msg = 'Bumping versions'; 51 | var type = args.type; 52 | var version = args.ver; 53 | var options = {}; 54 | if (version) { 55 | options.version = version; 56 | msg += ' to ' + version; 57 | } else { 58 | options.type = type; 59 | msg += ' for a ' + type; 60 | } 61 | log(msg); 62 | 63 | return gulp 64 | .src('package.json') 65 | // .pipe($.print()) 66 | .pipe($.bump(options)) 67 | .pipe(gulp.dest('./')); 68 | }); 69 | ////////// 70 | 71 | function build(done) { 72 | var builder = new Builder({ 73 | paths: {'*': '*.js'}, 74 | map: { 75 | angular2: 'node_modules/angular2', 76 | rxjs: 'node_modules/rxjs' 77 | }, 78 | meta: { 79 | 'angular2/*': { build: false }, 80 | 'rxjs/*': { build: false } 81 | }, 82 | packages: { 83 | 'angular2': { 84 | defaultExtension: 'js', 85 | main: 'core.js' 86 | }, 87 | 'rxjs': { 88 | defaultExtension: 'js', 89 | main: 'rx.js' 90 | } 91 | } 92 | }); 93 | 94 | builder 95 | // start building with the root module file in the folder with the intended module name 96 | .bundle('a2-in-memory-web-api/core', 'web-api.js') 97 | .then(function(output) { 98 | console.log('Build complete'); 99 | }) 100 | 101 | .catch(function(err) { 102 | console.log('Build error'); 103 | console.log(err); 104 | }) 105 | 106 | .finally(done); 107 | } 108 | 109 | function clean(path, done) { 110 | log('Cleaning: ' + $.util.colors.blue(path)); 111 | del(path, {dryRun:false}) 112 | .then(function(paths) { 113 | console.log('Deleted files and folders:\n', paths.join('\n')); 114 | }) 115 | .then(done,done); 116 | } 117 | 118 | function log(msg) { 119 | if (typeof(msg) === 'object') { 120 | for (var item in msg) { 121 | if (msg.hasOwnProperty(item)) { 122 | $.util.log($.util.colors.blue(msg[item])); 123 | } 124 | } 125 | } else { 126 | $.util.log($.util.colors.blue(msg)); 127 | } 128 | } 129 | function runTSC(directory, done) { 130 | directory = directory || './'; 131 | var tscjs = path.join(process.cwd(), 'node_modules/typescript/bin/tsc'); 132 | var childProcess = cp.spawn('node', [tscjs, '-p', directory], { cwd: process.cwd() }); 133 | childProcess.stdout.on('data', function (data) { 134 | console.log(data.toString()); 135 | }); 136 | childProcess.stderr.on('data', function (data) { 137 | console.log(data.toString()); 138 | }); 139 | childProcess.on('close', function () { 140 | done(); 141 | }); 142 | } 143 | 144 | // WILL THIS WORK? DOES IT PROMPT? 145 | function runTypings(done) { 146 | var typingsjs = path.join(process.cwd(), 'node_modules/typings/dist/bin/typings'); 147 | var childProcess = cp.spawn('node', [typingsjs, 'install'], { cwd: process.cwd() }); 148 | childProcess.stdout.on('data', function (data) { 149 | console.log(data.toString()); 150 | }); 151 | childProcess.stderr.on('data', function (data) { 152 | console.log(data.toString()); 153 | }); 154 | childProcess.on('close', function () { 155 | done(); 156 | }); 157 | } -------------------------------------------------------------------------------- /http-status-codes.d.ts: -------------------------------------------------------------------------------- 1 | export declare let STATUS: { 2 | CONTINUE: number; 3 | SWITCHING_PROTOCOLS: number; 4 | OK: number; 5 | CREATED: number; 6 | ACCEPTED: number; 7 | NON_AUTHORITATIVE_INFORMATION: number; 8 | NO_CONTENT: number; 9 | RESET_CONTENT: number; 10 | PARTIAL_CONTENT: number; 11 | MULTIPLE_CHOICES: number; 12 | MOVED_PERMANTENTLY: number; 13 | FOUND: number; 14 | SEE_OTHER: number; 15 | NOT_MODIFIED: number; 16 | USE_PROXY: number; 17 | TEMPORARY_REDIRECT: number; 18 | BAD_REQUEST: number; 19 | UNAUTHORIZED: number; 20 | PAYMENT_REQUIRED: number; 21 | FORBIDDEN: number; 22 | NOT_FOUND: number; 23 | METHOD_NOT_ALLOWED: number; 24 | NOT_ACCEPTABLE: number; 25 | PROXY_AUTHENTICATION_REQUIRED: number; 26 | REQUEST_TIMEOUT: number; 27 | CONFLICT: number; 28 | GONE: number; 29 | LENGTH_REQUIRED: number; 30 | PRECONDITION_FAILED: number; 31 | PAYLOAD_TO_LARGE: number; 32 | URI_TOO_LONG: number; 33 | UNSUPPORTED_MEDIA_TYPE: number; 34 | RANGE_NOT_SATISFIABLE: number; 35 | EXPECTATION_FAILED: number; 36 | IM_A_TEAPOT: number; 37 | UPGRADE_REQUIRED: number; 38 | INTERNAL_SERVER_ERROR: number; 39 | NOT_IMPLEMENTED: number; 40 | BAD_GATEWAY: number; 41 | SERVICE_UNAVAILABLE: number; 42 | GATEWAY_TIMEOUT: number; 43 | HTTP_VERSION_NOT_SUPPORTED: number; 44 | PROCESSING: number; 45 | MULTI_STATUS: number; 46 | IM_USED: number; 47 | PERMANENT_REDIRECT: number; 48 | UNPROCESSABLE_ENTRY: number; 49 | LOCKED: number; 50 | FAILED_DEPENDENCY: number; 51 | PRECONDITION_REQUIRED: number; 52 | TOO_MANY_REQUESTS: number; 53 | REQUEST_HEADER_FIELDS_TOO_LARGE: number; 54 | UNAVAILABLE_FOR_LEGAL_REASONS: number; 55 | VARIANT_ALSO_NEGOTIATES: number; 56 | INSUFFICIENT_STORAGE: number; 57 | NETWORK_AUTHENTICATION_REQUIRED: number; 58 | }; 59 | export declare let STATUS_CODE_INFO: { 60 | "100": { 61 | "code": number; 62 | "text": string; 63 | "description": string; 64 | "spec_title": string; 65 | "spec_href": string; 66 | }; 67 | "101": { 68 | "code": number; 69 | "text": string; 70 | "description": string; 71 | "spec_title": string; 72 | "spec_href": string; 73 | }; 74 | "102": { 75 | "code": number; 76 | "text": string; 77 | "description": string; 78 | "spec_title": string; 79 | "spec_href": string; 80 | }; 81 | "200": { 82 | "code": number; 83 | "text": string; 84 | "description": string; 85 | "spec_title": string; 86 | "spec_href": string; 87 | }; 88 | "201": { 89 | "code": number; 90 | "text": string; 91 | "description": string; 92 | "spec_title": string; 93 | "spec_href": string; 94 | }; 95 | "202": { 96 | "code": number; 97 | "text": string; 98 | "description": string; 99 | "spec_title": string; 100 | "spec_href": string; 101 | }; 102 | "203": { 103 | "code": number; 104 | "text": string; 105 | "description": string; 106 | "spec_title": string; 107 | "spec_href": string; 108 | }; 109 | "204": { 110 | "code": number; 111 | "text": string; 112 | "description": string; 113 | "spec_title": string; 114 | "spec_href": string; 115 | }; 116 | "205": { 117 | "code": number; 118 | "text": string; 119 | "description": string; 120 | "spec_title": string; 121 | "spec_href": string; 122 | }; 123 | "206": { 124 | "code": number; 125 | "text": string; 126 | "description": string; 127 | "spec_title": string; 128 | "spec_href": string; 129 | }; 130 | "207": { 131 | "code": number; 132 | "text": string; 133 | "description": string; 134 | "spec_title": string; 135 | "spec_href": string; 136 | }; 137 | "226": { 138 | "code": number; 139 | "text": string; 140 | "description": string; 141 | "spec_title": string; 142 | "spec_href": string; 143 | }; 144 | "300": { 145 | "code": number; 146 | "text": string; 147 | "description": string; 148 | "spec_title": string; 149 | "spec_href": string; 150 | }; 151 | "301": { 152 | "code": number; 153 | "text": string; 154 | "description": string; 155 | "spec_title": string; 156 | "spec_href": string; 157 | }; 158 | "302": { 159 | "code": number; 160 | "text": string; 161 | "description": string; 162 | "spec_title": string; 163 | "spec_href": string; 164 | }; 165 | "303": { 166 | "code": number; 167 | "text": string; 168 | "description": string; 169 | "spec_title": string; 170 | "spec_href": string; 171 | }; 172 | "304": { 173 | "code": number; 174 | "text": string; 175 | "description": string; 176 | "spec_title": string; 177 | "spec_href": string; 178 | }; 179 | "305": { 180 | "code": number; 181 | "text": string; 182 | "description": string; 183 | "spec_title": string; 184 | "spec_href": string; 185 | }; 186 | "307": { 187 | "code": number; 188 | "text": string; 189 | "description": string; 190 | "spec_title": string; 191 | "spec_href": string; 192 | }; 193 | "308": { 194 | "code": number; 195 | "text": string; 196 | "description": string; 197 | "spec_title": string; 198 | "spec_href": string; 199 | }; 200 | "400": { 201 | "code": number; 202 | "text": string; 203 | "description": string; 204 | "spec_title": string; 205 | "spec_href": string; 206 | }; 207 | "401": { 208 | "code": number; 209 | "text": string; 210 | "description": string; 211 | "spec_title": string; 212 | "spec_href": string; 213 | }; 214 | "402": { 215 | "code": number; 216 | "text": string; 217 | "description": string; 218 | "spec_title": string; 219 | "spec_href": string; 220 | }; 221 | "403": { 222 | "code": number; 223 | "text": string; 224 | "description": string; 225 | "spec_title": string; 226 | "spec_href": string; 227 | }; 228 | "404": { 229 | "code": number; 230 | "text": string; 231 | "description": string; 232 | "spec_title": string; 233 | "spec_href": string; 234 | }; 235 | "405": { 236 | "code": number; 237 | "text": string; 238 | "description": string; 239 | "spec_title": string; 240 | "spec_href": string; 241 | }; 242 | "406": { 243 | "code": number; 244 | "text": string; 245 | "description": string; 246 | "spec_title": string; 247 | "spec_href": string; 248 | }; 249 | "407": { 250 | "code": number; 251 | "text": string; 252 | "description": string; 253 | "spec_title": string; 254 | "spec_href": string; 255 | }; 256 | "408": { 257 | "code": number; 258 | "text": string; 259 | "description": string; 260 | "spec_title": string; 261 | "spec_href": string; 262 | }; 263 | "409": { 264 | "code": number; 265 | "text": string; 266 | "description": string; 267 | "spec_title": string; 268 | "spec_href": string; 269 | }; 270 | "410": { 271 | "code": number; 272 | "text": string; 273 | "description": string; 274 | "spec_title": string; 275 | "spec_href": string; 276 | }; 277 | "411": { 278 | "code": number; 279 | "text": string; 280 | "description": string; 281 | "spec_title": string; 282 | "spec_href": string; 283 | }; 284 | "412": { 285 | "code": number; 286 | "text": string; 287 | "description": string; 288 | "spec_title": string; 289 | "spec_href": string; 290 | }; 291 | "413": { 292 | "code": number; 293 | "text": string; 294 | "description": string; 295 | "spec_title": string; 296 | "spec_href": string; 297 | }; 298 | "414": { 299 | "code": number; 300 | "text": string; 301 | "description": string; 302 | "spec_title": string; 303 | "spec_href": string; 304 | }; 305 | "415": { 306 | "code": number; 307 | "text": string; 308 | "description": string; 309 | "spec_title": string; 310 | "spec_href": string; 311 | }; 312 | "416": { 313 | "code": number; 314 | "text": string; 315 | "description": string; 316 | "spec_title": string; 317 | "spec_href": string; 318 | }; 319 | "417": { 320 | "code": number; 321 | "text": string; 322 | "description": string; 323 | "spec_title": string; 324 | "spec_href": string; 325 | }; 326 | "418": { 327 | "code": number; 328 | "text": string; 329 | "description": string; 330 | "spec_title": string; 331 | "spec_href": string; 332 | }; 333 | "422": { 334 | "code": number; 335 | "text": string; 336 | "description": string; 337 | "spec_title": string; 338 | "spec_href": string; 339 | }; 340 | "423": { 341 | "code": number; 342 | "text": string; 343 | "description": string; 344 | "spec_title": string; 345 | "spec_href": string; 346 | }; 347 | "424": { 348 | "code": number; 349 | "text": string; 350 | "description": string; 351 | "spec_title": string; 352 | "spec_href": string; 353 | }; 354 | "426": { 355 | "code": number; 356 | "text": string; 357 | "description": string; 358 | "spec_title": string; 359 | "spec_href": string; 360 | }; 361 | "428": { 362 | "code": number; 363 | "text": string; 364 | "description": string; 365 | "spec_title": string; 366 | "spec_href": string; 367 | }; 368 | "429": { 369 | "code": number; 370 | "text": string; 371 | "description": string; 372 | "spec_title": string; 373 | "spec_href": string; 374 | }; 375 | "431": { 376 | "code": number; 377 | "text": string; 378 | "description": string; 379 | "spec_title": string; 380 | "spec_href": string; 381 | }; 382 | "451": { 383 | "code": number; 384 | "text": string; 385 | "description": string; 386 | "spec_title": string; 387 | "spec_href": string; 388 | }; 389 | "500": { 390 | "code": number; 391 | "text": string; 392 | "description": string; 393 | "spec_title": string; 394 | "spec_href": string; 395 | }; 396 | "501": { 397 | "code": number; 398 | "text": string; 399 | "description": string; 400 | "spec_title": string; 401 | "spec_href": string; 402 | }; 403 | "502": { 404 | "code": number; 405 | "text": string; 406 | "description": string; 407 | "spec_title": string; 408 | "spec_href": string; 409 | }; 410 | "503": { 411 | "code": number; 412 | "text": string; 413 | "description": string; 414 | "spec_title": string; 415 | "spec_href": string; 416 | }; 417 | "504": { 418 | "code": number; 419 | "text": string; 420 | "description": string; 421 | "spec_title": string; 422 | "spec_href": string; 423 | }; 424 | "505": { 425 | "code": number; 426 | "text": string; 427 | "description": string; 428 | "spec_title": string; 429 | "spec_href": string; 430 | }; 431 | "506": { 432 | "code": number; 433 | "text": string; 434 | "description": string; 435 | "spec_title": string; 436 | "spec_href": string; 437 | }; 438 | "507": { 439 | "code": number; 440 | "text": string; 441 | "description": string; 442 | "spec_title": string; 443 | "spec_href": string; 444 | }; 445 | "511": { 446 | "code": number; 447 | "text": string; 448 | "description": string; 449 | "spec_title": string; 450 | "spec_href": string; 451 | }; 452 | }; 453 | -------------------------------------------------------------------------------- /http-status-codes.js: -------------------------------------------------------------------------------- 1 | System.register([], function(exports_1, context_1) { 2 | "use strict"; 3 | var __moduleName = context_1 && context_1.id; 4 | var STATUS, STATUS_CODE_INFO; 5 | return { 6 | setters:[], 7 | execute: function() { 8 | exports_1("STATUS", STATUS = { 9 | CONTINUE: 100, 10 | SWITCHING_PROTOCOLS: 101, 11 | OK: 200, 12 | CREATED: 201, 13 | ACCEPTED: 202, 14 | NON_AUTHORITATIVE_INFORMATION: 203, 15 | NO_CONTENT: 204, 16 | RESET_CONTENT: 205, 17 | PARTIAL_CONTENT: 206, 18 | MULTIPLE_CHOICES: 300, 19 | MOVED_PERMANTENTLY: 301, 20 | FOUND: 302, 21 | SEE_OTHER: 303, 22 | NOT_MODIFIED: 304, 23 | USE_PROXY: 305, 24 | TEMPORARY_REDIRECT: 307, 25 | BAD_REQUEST: 400, 26 | UNAUTHORIZED: 401, 27 | PAYMENT_REQUIRED: 402, 28 | FORBIDDEN: 403, 29 | NOT_FOUND: 404, 30 | METHOD_NOT_ALLOWED: 405, 31 | NOT_ACCEPTABLE: 406, 32 | PROXY_AUTHENTICATION_REQUIRED: 407, 33 | REQUEST_TIMEOUT: 408, 34 | CONFLICT: 409, 35 | GONE: 410, 36 | LENGTH_REQUIRED: 411, 37 | PRECONDITION_FAILED: 412, 38 | PAYLOAD_TO_LARGE: 413, 39 | URI_TOO_LONG: 414, 40 | UNSUPPORTED_MEDIA_TYPE: 415, 41 | RANGE_NOT_SATISFIABLE: 416, 42 | EXPECTATION_FAILED: 417, 43 | IM_A_TEAPOT: 418, 44 | UPGRADE_REQUIRED: 426, 45 | INTERNAL_SERVER_ERROR: 500, 46 | NOT_IMPLEMENTED: 501, 47 | BAD_GATEWAY: 502, 48 | SERVICE_UNAVAILABLE: 503, 49 | GATEWAY_TIMEOUT: 504, 50 | HTTP_VERSION_NOT_SUPPORTED: 505, 51 | PROCESSING: 102, 52 | MULTI_STATUS: 207, 53 | IM_USED: 226, 54 | PERMANENT_REDIRECT: 308, 55 | UNPROCESSABLE_ENTRY: 422, 56 | LOCKED: 423, 57 | FAILED_DEPENDENCY: 424, 58 | PRECONDITION_REQUIRED: 428, 59 | TOO_MANY_REQUESTS: 429, 60 | REQUEST_HEADER_FIELDS_TOO_LARGE: 431, 61 | UNAVAILABLE_FOR_LEGAL_REASONS: 451, 62 | VARIANT_ALSO_NEGOTIATES: 506, 63 | INSUFFICIENT_STORAGE: 507, 64 | NETWORK_AUTHENTICATION_REQUIRED: 511 65 | }); 66 | exports_1("STATUS_CODE_INFO", STATUS_CODE_INFO = { 67 | "100": { 68 | "code": 100, 69 | "text": "Continue", 70 | "description": "\"The initial part of a request has been received and has not yet been rejected by the server.\"", 71 | "spec_title": "RFC7231#6.2.1", 72 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.1" 73 | }, 74 | "101": { 75 | "code": 101, 76 | "text": "Switching Protocols", 77 | "description": "\"The server understands and is willing to comply with the client's request, via the Upgrade header field, for a change in the application protocol being used on this connection.\"", 78 | "spec_title": "RFC7231#6.2.2", 79 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.2" 80 | }, 81 | "200": { 82 | "code": 200, 83 | "text": "OK", 84 | "description": "\"The request has succeeded.\"", 85 | "spec_title": "RFC7231#6.3.1", 86 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.1" 87 | }, 88 | "201": { 89 | "code": 201, 90 | "text": "Created", 91 | "description": "\"The request has been fulfilled and has resulted in one or more new resources being created.\"", 92 | "spec_title": "RFC7231#6.3.2", 93 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 94 | }, 95 | "202": { 96 | "code": 202, 97 | "text": "Accepted", 98 | "description": "\"The request has been accepted for processing, but the processing has not been completed.\"", 99 | "spec_title": "RFC7231#6.3.3", 100 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.3" 101 | }, 102 | "203": { 103 | "code": 203, 104 | "text": "Non-Authoritative Information", 105 | "description": "\"The request was successful but the enclosed payload has been modified from that of the origin server's 200 (OK) response by a transforming proxy.\"", 106 | "spec_title": "RFC7231#6.3.4", 107 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.4" 108 | }, 109 | "204": { 110 | "code": 204, 111 | "text": "No Content", 112 | "description": "\"The server has successfully fulfilled the request and that there is no additional content to send in the response payload body.\"", 113 | "spec_title": "RFC7231#6.3.5", 114 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.5" 115 | }, 116 | "205": { 117 | "code": 205, 118 | "text": "Reset Content", 119 | "description": "\"The server has fulfilled the request and desires that the user agent reset the \"document view\", which caused the request to be sent, to its original state as received from the origin server.\"", 120 | "spec_title": "RFC7231#6.3.6", 121 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.6" 122 | }, 123 | "206": { 124 | "code": 206, 125 | "text": "Partial Content", 126 | "description": "\"The server is successfully fulfilling a range request for the target resource by transferring one or more parts of the selected representation that correspond to the satisfiable ranges found in the requests's Range header field.\"", 127 | "spec_title": "RFC7233#4.1", 128 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.1" 129 | }, 130 | "300": { 131 | "code": 300, 132 | "text": "Multiple Choices", 133 | "description": "\"The target resource has more than one representation, each with its own more specific identifier, and information about the alternatives is being provided so that the user (or user agent) can select a preferred representation by redirecting its request to one or more of those identifiers.\"", 134 | "spec_title": "RFC7231#6.4.1", 135 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.1" 136 | }, 137 | "301": { 138 | "code": 301, 139 | "text": "Moved Permanently", 140 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs.\"", 141 | "spec_title": "RFC7231#6.4.2", 142 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.2" 143 | }, 144 | "302": { 145 | "code": 302, 146 | "text": "Found", 147 | "description": "\"The target resource resides temporarily under a different URI.\"", 148 | "spec_title": "RFC7231#6.4.3", 149 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.3" 150 | }, 151 | "303": { 152 | "code": 303, 153 | "text": "See Other", 154 | "description": "\"The server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field, that is intended to provide an indirect response to the original request.\"", 155 | "spec_title": "RFC7231#6.4.4", 156 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.4" 157 | }, 158 | "304": { 159 | "code": 304, 160 | "text": "Not Modified", 161 | "description": "\"A conditional GET request has been received and would have resulted in a 200 (OK) response if it were not for the fact that the condition has evaluated to false.\"", 162 | "spec_title": "RFC7232#4.1", 163 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.1" 164 | }, 165 | "305": { 166 | "code": 305, 167 | "text": "Use Proxy", 168 | "description": "*deprecated*", 169 | "spec_title": "RFC7231#6.4.5", 170 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.5" 171 | }, 172 | "307": { 173 | "code": 307, 174 | "text": "Temporary Redirect", 175 | "description": "\"The target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI.\"", 176 | "spec_title": "RFC7231#6.4.7", 177 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.7" 178 | }, 179 | "400": { 180 | "code": 400, 181 | "text": "Bad Request", 182 | "description": "\"The server cannot or will not process the request because the received syntax is invalid, nonsensical, or exceeds some limitation on what the server is willing to process.\"", 183 | "spec_title": "RFC7231#6.5.1", 184 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.1" 185 | }, 186 | "401": { 187 | "code": 401, 188 | "text": "Unauthorized", 189 | "description": "\"The request has not been applied because it lacks valid authentication credentials for the target resource.\"", 190 | "spec_title": "RFC7235#6.3.1", 191 | "spec_href": "http://tools.ietf.org/html/rfc7235#section-3.1" 192 | }, 193 | "402": { 194 | "code": 402, 195 | "text": "Payment Required", 196 | "description": "*reserved*", 197 | "spec_title": "RFC7231#6.5.2", 198 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.2" 199 | }, 200 | "403": { 201 | "code": 403, 202 | "text": "Forbidden", 203 | "description": "\"The server understood the request but refuses to authorize it.\"", 204 | "spec_title": "RFC7231#6.5.3", 205 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.3" 206 | }, 207 | "404": { 208 | "code": 404, 209 | "text": "Not Found", 210 | "description": "\"The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.\"", 211 | "spec_title": "RFC7231#6.5.4", 212 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.4" 213 | }, 214 | "405": { 215 | "code": 405, 216 | "text": "Method Not Allowed", 217 | "description": "\"The method specified in the request-line is known by the origin server but not supported by the target resource.\"", 218 | "spec_title": "RFC7231#6.5.5", 219 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.5" 220 | }, 221 | "406": { 222 | "code": 406, 223 | "text": "Not Acceptable", 224 | "description": "\"The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.\"", 225 | "spec_title": "RFC7231#6.5.6", 226 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.6" 227 | }, 228 | "407": { 229 | "code": 407, 230 | "text": "Proxy Authentication Required", 231 | "description": "\"The client needs to authenticate itself in order to use a proxy.\"", 232 | "spec_title": "RFC7231#6.3.2", 233 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 234 | }, 235 | "408": { 236 | "code": 408, 237 | "text": "Request Timeout", 238 | "description": "\"The server did not receive a complete request message within the time that it was prepared to wait.\"", 239 | "spec_title": "RFC7231#6.5.7", 240 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.7" 241 | }, 242 | "409": { 243 | "code": 409, 244 | "text": "Conflict", 245 | "description": "\"The request could not be completed due to a conflict with the current state of the resource.\"", 246 | "spec_title": "RFC7231#6.5.8", 247 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.8" 248 | }, 249 | "410": { 250 | "code": 410, 251 | "text": "Gone", 252 | "description": "\"Access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.\"", 253 | "spec_title": "RFC7231#6.5.9", 254 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.9" 255 | }, 256 | "411": { 257 | "code": 411, 258 | "text": "Length Required", 259 | "description": "\"The server refuses to accept the request without a defined Content-Length.\"", 260 | "spec_title": "RFC7231#6.5.10", 261 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.10" 262 | }, 263 | "412": { 264 | "code": 412, 265 | "text": "Precondition Failed", 266 | "description": "\"One or more preconditions given in the request header fields evaluated to false when tested on the server.\"", 267 | "spec_title": "RFC7232#4.2", 268 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.2" 269 | }, 270 | "413": { 271 | "code": 413, 272 | "text": "Payload Too Large", 273 | "description": "\"The server is refusing to process a request because the request payload is larger than the server is willing or able to process.\"", 274 | "spec_title": "RFC7231#6.5.11", 275 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.11" 276 | }, 277 | "414": { 278 | "code": 414, 279 | "text": "URI Too Long", 280 | "description": "\"The server is refusing to service the request because the request-target is longer than the server is willing to interpret.\"", 281 | "spec_title": "RFC7231#6.5.12", 282 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.12" 283 | }, 284 | "415": { 285 | "code": 415, 286 | "text": "Unsupported Media Type", 287 | "description": "\"The origin server is refusing to service the request because the payload is in a format not supported by the target resource for this method.\"", 288 | "spec_title": "RFC7231#6.5.13", 289 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.13" 290 | }, 291 | "416": { 292 | "code": 416, 293 | "text": "Range Not Satisfiable", 294 | "description": "\"None of the ranges in the request's Range header field overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges.\"", 295 | "spec_title": "RFC7233#4.4", 296 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.4" 297 | }, 298 | "417": { 299 | "code": 417, 300 | "text": "Expectation Failed", 301 | "description": "\"The expectation given in the request's Expect header field could not be met by at least one of the inbound servers.\"", 302 | "spec_title": "RFC7231#6.5.14", 303 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.14" 304 | }, 305 | "418": { 306 | "code": 418, 307 | "text": "I'm a teapot", 308 | "description": "\"1988 April Fools Joke. Returned by tea pots requested to brew coffee.\"", 309 | "spec_title": "RFC 2324", 310 | "spec_href": "https://tools.ietf.org/html/rfc2324" 311 | }, 312 | "426": { 313 | "code": 426, 314 | "text": "Upgrade Required", 315 | "description": "\"The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol.\"", 316 | "spec_title": "RFC7231#6.5.15", 317 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.15" 318 | }, 319 | "500": { 320 | "code": 500, 321 | "text": "Internal Server Error", 322 | "description": "\"The server encountered an unexpected condition that prevented it from fulfilling the request.\"", 323 | "spec_title": "RFC7231#6.6.1", 324 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.1" 325 | }, 326 | "501": { 327 | "code": 501, 328 | "text": "Not Implemented", 329 | "description": "\"The server does not support the functionality required to fulfill the request.\"", 330 | "spec_title": "RFC7231#6.6.2", 331 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.2" 332 | }, 333 | "502": { 334 | "code": 502, 335 | "text": "Bad Gateway", 336 | "description": "\"The server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.\"", 337 | "spec_title": "RFC7231#6.6.3", 338 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.3" 339 | }, 340 | "503": { 341 | "code": 503, 342 | "text": "Service Unavailable", 343 | "description": "\"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.\"", 344 | "spec_title": "RFC7231#6.6.4", 345 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.4" 346 | }, 347 | "504": { 348 | "code": 504, 349 | "text": "Gateway Time-out", 350 | "description": "\"The server, while acting as a gateway or proxy, did not receive a timely response from an upstream server it needed to access in order to complete the request.\"", 351 | "spec_title": "RFC7231#6.6.5", 352 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.5" 353 | }, 354 | "505": { 355 | "code": 505, 356 | "text": "HTTP Version Not Supported", 357 | "description": "\"The server does not support, or refuses to support, the protocol version that was used in the request message.\"", 358 | "spec_title": "RFC7231#6.6.6", 359 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.6" 360 | }, 361 | "102": { 362 | "code": 102, 363 | "text": "Processing", 364 | "description": "\"An interim response to inform the client that the server has accepted the complete request, but has not yet completed it.\"", 365 | "spec_title": "RFC5218#10.1", 366 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.1" 367 | }, 368 | "207": { 369 | "code": 207, 370 | "text": "Multi-Status", 371 | "description": "\"Status for multiple independent operations.\"", 372 | "spec_title": "RFC5218#10.2", 373 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.2" 374 | }, 375 | "226": { 376 | "code": 226, 377 | "text": "IM Used", 378 | "description": "\"The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance.\"", 379 | "spec_title": "RFC3229#10.4.1", 380 | "spec_href": "http://tools.ietf.org/html/rfc3229#section-10.4.1" 381 | }, 382 | "308": { 383 | "code": 308, 384 | "text": "Permanent Redirect", 385 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. [...] This status code is similar to 301 Moved Permanently (Section 7.3.2 of rfc7231), except that it does not allow rewriting the request method from POST to GET.\"", 386 | "spec_title": "RFC7238", 387 | "spec_href": "http://tools.ietf.org/html/rfc7238" 388 | }, 389 | "422": { 390 | "code": 422, 391 | "text": "Unprocessable Entity", 392 | "description": "\"The server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions.\"", 393 | "spec_title": "RFC5218#10.3", 394 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.3" 395 | }, 396 | "423": { 397 | "code": 423, 398 | "text": "Locked", 399 | "description": "\"The source or destination resource of a method is locked.\"", 400 | "spec_title": "RFC5218#10.4", 401 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.4" 402 | }, 403 | "424": { 404 | "code": 424, 405 | "text": "Failed Dependency", 406 | "description": "\"The method could not be performed on the resource because the requested action depended on another action and that action failed.\"", 407 | "spec_title": "RFC5218#10.5", 408 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.5" 409 | }, 410 | "428": { 411 | "code": 428, 412 | "text": "Precondition Required", 413 | "description": "\"The origin server requires the request to be conditional.\"", 414 | "spec_title": "RFC6585#3", 415 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-3" 416 | }, 417 | "429": { 418 | "code": 429, 419 | "text": "Too Many Requests", 420 | "description": "\"The user has sent too many requests in a given amount of time (\"rate limiting\").\"", 421 | "spec_title": "RFC6585#4", 422 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-4" 423 | }, 424 | "431": { 425 | "code": 431, 426 | "text": "Request Header Fields Too Large", 427 | "description": "\"The server is unwilling to process the request because its header fields are too large.\"", 428 | "spec_title": "RFC6585#5", 429 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-5" 430 | }, 431 | "451": { 432 | "code": 451, 433 | "text": "Unavailable For Legal Reasons", 434 | "description": "\"The server is denying access to the resource in response to a legal demand.\"", 435 | "spec_title": "draft-ietf-httpbis-legally-restricted-status", 436 | "spec_href": "http://tools.ietf.org/html/draft-ietf-httpbis-legally-restricted-status" 437 | }, 438 | "506": { 439 | "code": 506, 440 | "text": "Variant Also Negotiates", 441 | "description": "\"The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.\"", 442 | "spec_title": "RFC2295#8.1", 443 | "spec_href": "http://tools.ietf.org/html/rfc2295#section-8.1" 444 | }, 445 | "507": { 446 | "code": 507, 447 | "text": "Insufficient Storage", 448 | "description": "\The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request.\"", 449 | "spec_title": "RFC5218#10.6", 450 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.6" 451 | }, 452 | "511": { 453 | "code": 511, 454 | "text": "Network Authentication Required", 455 | "description": "\"The client needs to authenticate to gain network access.\"", 456 | "spec_title": "RFC6585#6", 457 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-6" 458 | } 459 | }); 460 | } 461 | } 462 | }); 463 | //# sourceMappingURL=http-status-codes.js.map -------------------------------------------------------------------------------- /in-memory-backend.service.d.ts: -------------------------------------------------------------------------------- 1 | import { OpaqueToken } from 'angular2/core'; 2 | import { Headers, Request, Response, ResponseOptions } from 'angular2/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import 'rxjs/add/operator/delay'; 5 | /** 6 | * Seed data for in-memory database 7 | * Must implement InMemoryDbService. 8 | */ 9 | export declare const SEED_DATA: OpaqueToken; 10 | /** 11 | * Interface for a class that creates an in-memory database 12 | * Safe for consuming service to morph arrays and objects. 13 | */ 14 | export interface InMemoryDbService { 15 | /** 16 | * Creates "database" object hash whose keys are collection names 17 | * and whose values are arrays of the collection objects. 18 | * 19 | * It must be safe to call again and should return new arrays with new objects. 20 | * This condition allows InMemoryBackendService to morph the arrays and objects 21 | * without touching the original source data. 22 | */ 23 | createDb(): {}; 24 | } 25 | /** 26 | * Interface for InMemoryBackend configuration options 27 | */ 28 | export interface InMemoryBackendConfigArgs { 29 | /** 30 | * default response options 31 | */ 32 | defaultResponseOptions?: ResponseOptions; 33 | /** 34 | * delay (in ms) to simulate latency 35 | */ 36 | delay?: number; 37 | /** 38 | * false (default) if ok when object-to-delete not found; else 404 39 | */ 40 | delete404?: boolean; 41 | /** 42 | * host for this service 43 | */ 44 | host?: string; 45 | /** 46 | * root path before any API call 47 | */ 48 | rootPath?: string; 49 | } 50 | /** 51 | * InMemoryBackendService configuration options 52 | * Usage: 53 | * provide(InMemoryBackendConfig, {useValue: {delay:600}}), 54 | */ 55 | export declare class InMemoryBackendConfig implements InMemoryBackendConfigArgs { 56 | constructor(config?: InMemoryBackendConfigArgs); 57 | } 58 | /** 59 | * Interface for object w/ info about the current request url 60 | * extracted from an Http Request 61 | */ 62 | export interface ReqInfo { 63 | req: Request; 64 | base: string; 65 | collection: any[]; 66 | collectionName: string; 67 | headers: Headers; 68 | id: any; 69 | resourceUrl: string; 70 | } 71 | export declare const isSuccess: (status: number) => boolean; 72 | /** 73 | * Simulate the behavior of a RESTy web api 74 | * backed by the simple in-memory data store provided by the injected InMemoryDataService service. 75 | * Conforms mostly to behavior described here: 76 | * http://www.restapitutorial.com/lessons/httpmethods.html 77 | * 78 | * ### Usage 79 | * 80 | * Create InMemoryDataService class the implements IInMemoryDataService. 81 | * Register both this service and the seed data as in: 82 | * ``` 83 | * // other imports 84 | * import { HTTP_PROVIDERS, XHRBackend } from 'angular2/http'; 85 | * import { InMemoryBackendConfig, InMemoryBackendService, SEED_DATA } from '../in-memory-backend/in-memory-backend.service'; 86 | * import { InMemoryStoryService } from '../api/in-memory-story.service'; 87 | * 88 | * @Component({ 89 | * selector: ..., 90 | * templateUrl: ..., 91 | * providers: [ 92 | * HTTP_PROVIDERS, 93 | * provide(XHRBackend, { useClass: InMemoryBackendService }), 94 | * provide(SEED_DATA, { useClass: InMemoryStoryService }), 95 | * provide(InMemoryBackendConfig, { useValue: { delay: 600 } }), 96 | * ] 97 | * }) 98 | * export class AppComponent { ... } 99 | * ``` 100 | */ 101 | export declare class InMemoryBackendService { 102 | private _seedData; 103 | protected _config: InMemoryBackendConfigArgs; 104 | protected _db: {}; 105 | constructor(_seedData: InMemoryDbService, config: InMemoryBackendConfigArgs); 106 | createConnection(req: Request): { 107 | response: Observable<{}>; 108 | }; 109 | /** 110 | * Process Request and return an Http Response object 111 | * in the manner of a RESTy web api. 112 | * 113 | * Expect URI pattern in the form :base/:collectionName/:id? 114 | * Examples: 115 | * api/characters 116 | * api/characters/42 117 | * api/characters.json/42 // ignores the ".json" 118 | * commands/resetDb // resets the "database" 119 | */ 120 | protected _handleRequest(req: Request): Response; 121 | protected _clone(data: any): any; 122 | /** 123 | * When the `base`="commands", the `collectionName` is the command 124 | * Example URLs: 125 | * commands/resetdb // Reset the "database" to its original state 126 | * commands/config (GET) // Return this service's config object 127 | * commands/config (!GET) // Update the config (e.g. delay) 128 | * 129 | * Usage: 130 | * http.post('commands/resetdb', null); 131 | * http.get('commands/config'); 132 | * http.post('commands/config', '{"delay":1000}'); 133 | */ 134 | protected _commands(reqInfo: ReqInfo): ResponseOptions; 135 | protected _createErrorResponse(status: number, message: string): ResponseOptions; 136 | protected _delete({id, collection, collectionName, headers}: ReqInfo): ResponseOptions; 137 | protected _findById(collection: any[], id: number): any; 138 | protected _genId(collection: any): any; 139 | protected _get({id, collection, collectionName, headers}: ReqInfo): ResponseOptions; 140 | protected _getLocation(href: string): HTMLAnchorElement; 141 | protected _indexOf(collection: any[], id: number): number; 142 | protected _parseId(id: string): any; 143 | protected _parseUrl(url: string): { 144 | base: string; 145 | id: string; 146 | collectionName: string; 147 | resourceUrl: string; 148 | }; 149 | protected _post({collection, headers, id, req, resourceUrl}: ReqInfo): ResponseOptions; 150 | protected _put({id, collection, collectionName, headers, req}: ReqInfo): ResponseOptions; 151 | protected _removeById(collection: any[], id: number): boolean; 152 | /** 153 | * Reset the "database" to its original state 154 | */ 155 | protected _resetDb(): void; 156 | protected _setStatusText(options: ResponseOptions): ResponseOptions; 157 | } 158 | -------------------------------------------------------------------------------- /in-memory-backend.service.js: -------------------------------------------------------------------------------- 1 | System.register(['angular2/core', 'angular2/http', 'rxjs/Observable', 'rxjs/add/operator/delay', './http-status-codes'], function(exports_1, context_1) { 2 | "use strict"; 3 | var __moduleName = context_1 && context_1.id; 4 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 5 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 6 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 7 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 8 | return c > 3 && r && Object.defineProperty(target, key, r), r; 9 | }; 10 | var __metadata = (this && this.__metadata) || function (k, v) { 11 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 12 | }; 13 | var __param = (this && this.__param) || function (paramIndex, decorator) { 14 | return function (target, key) { decorator(target, key, paramIndex); } 15 | }; 16 | var core_1, http_1, Observable_1, http_status_codes_1; 17 | var SEED_DATA, InMemoryBackendConfig, isSuccess, InMemoryBackendService; 18 | return { 19 | setters:[ 20 | function (core_1_1) { 21 | core_1 = core_1_1; 22 | }, 23 | function (http_1_1) { 24 | http_1 = http_1_1; 25 | }, 26 | function (Observable_1_1) { 27 | Observable_1 = Observable_1_1; 28 | }, 29 | function (_1) {}, 30 | function (http_status_codes_1_1) { 31 | http_status_codes_1 = http_status_codes_1_1; 32 | }], 33 | execute: function() { 34 | /** 35 | * Seed data for in-memory database 36 | * Must implement InMemoryDbService. 37 | */ 38 | exports_1("SEED_DATA", SEED_DATA = new core_1.OpaqueToken('seedData')); 39 | /** 40 | * InMemoryBackendService configuration options 41 | * Usage: 42 | * provide(InMemoryBackendConfig, {useValue: {delay:600}}), 43 | */ 44 | InMemoryBackendConfig = (function () { 45 | function InMemoryBackendConfig(config) { 46 | if (config === void 0) { config = {}; } 47 | Object.assign(this, { 48 | defaultResponseOptions: new http_1.BaseResponseOptions(), 49 | delay: 500, 50 | delete404: false 51 | }, config); 52 | } 53 | return InMemoryBackendConfig; 54 | }()); 55 | exports_1("InMemoryBackendConfig", InMemoryBackendConfig); 56 | exports_1("isSuccess", isSuccess = function (status) { return (status >= 200 && status < 300); }); 57 | /** 58 | * Simulate the behavior of a RESTy web api 59 | * backed by the simple in-memory data store provided by the injected InMemoryDataService service. 60 | * Conforms mostly to behavior described here: 61 | * http://www.restapitutorial.com/lessons/httpmethods.html 62 | * 63 | * ### Usage 64 | * 65 | * Create InMemoryDataService class the implements IInMemoryDataService. 66 | * Register both this service and the seed data as in: 67 | * ``` 68 | * // other imports 69 | * import { HTTP_PROVIDERS, XHRBackend } from 'angular2/http'; 70 | * import { InMemoryBackendConfig, InMemoryBackendService, SEED_DATA } from '../in-memory-backend/in-memory-backend.service'; 71 | * import { InMemoryStoryService } from '../api/in-memory-story.service'; 72 | * 73 | * @Component({ 74 | * selector: ..., 75 | * templateUrl: ..., 76 | * providers: [ 77 | * HTTP_PROVIDERS, 78 | * provide(XHRBackend, { useClass: InMemoryBackendService }), 79 | * provide(SEED_DATA, { useClass: InMemoryStoryService }), 80 | * provide(InMemoryBackendConfig, { useValue: { delay: 600 } }), 81 | * ] 82 | * }) 83 | * export class AppComponent { ... } 84 | * ``` 85 | */ 86 | InMemoryBackendService = (function () { 87 | function InMemoryBackendService(_seedData, config) { 88 | this._seedData = _seedData; 89 | this._config = new InMemoryBackendConfig(); 90 | this._resetDb(); 91 | var loc = this._getLocation('./'); 92 | this._config.host = loc.host; 93 | this._config.rootPath = loc.pathname; 94 | Object.assign(this._config, config); 95 | } 96 | InMemoryBackendService.prototype.createConnection = function (req) { 97 | var res = this._handleRequest(req); 98 | var response = new Observable_1.Observable(function (responseObserver) { 99 | if (isSuccess(res.status)) { 100 | responseObserver.next(res); 101 | responseObserver.complete(); 102 | } 103 | else { 104 | responseObserver.error(res); 105 | } 106 | return function () { }; // unsubscribe function 107 | }); 108 | response = response.delay(this._config.delay || 500); 109 | return { response: response }; 110 | }; 111 | //// protected ///// 112 | /** 113 | * Process Request and return an Http Response object 114 | * in the manner of a RESTy web api. 115 | * 116 | * Expect URI pattern in the form :base/:collectionName/:id? 117 | * Examples: 118 | * api/characters 119 | * api/characters/42 120 | * api/characters.json/42 // ignores the ".json" 121 | * commands/resetDb // resets the "database" 122 | */ 123 | InMemoryBackendService.prototype._handleRequest = function (req) { 124 | var _a = this._parseUrl(req.url), base = _a.base, collectionName = _a.collectionName, id = _a.id, resourceUrl = _a.resourceUrl; 125 | var reqInfo = { 126 | req: req, 127 | base: base, 128 | collection: this._db[collectionName], 129 | collectionName: collectionName, 130 | headers: new http_1.Headers({ 'Content-Type': 'application/json' }), 131 | id: this._parseId(id), 132 | resourceUrl: resourceUrl 133 | }; 134 | var options; 135 | try { 136 | if ('commands' === reqInfo.base.toLowerCase()) { 137 | options = this._commands(reqInfo); 138 | } 139 | else if (reqInfo.collection) { 140 | switch (req.method) { 141 | case http_1.RequestMethod.Get: 142 | options = this._get(reqInfo); 143 | break; 144 | case http_1.RequestMethod.Post: 145 | options = this._post(reqInfo); 146 | break; 147 | case http_1.RequestMethod.Put: 148 | options = this._put(reqInfo); 149 | break; 150 | case http_1.RequestMethod.Delete: 151 | options = this._delete(reqInfo); 152 | break; 153 | default: 154 | options = this._createErrorResponse(http_status_codes_1.STATUS.METHOD_NOT_ALLOWED, 'Method not allowed'); 155 | break; 156 | } 157 | } 158 | else { 159 | options = this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Collection '" + collectionName + "' not found"); 160 | } 161 | } 162 | catch (error) { 163 | var err = error.message || error; 164 | options = this._createErrorResponse(http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, "" + err); 165 | } 166 | options = this._setStatusText(options); 167 | if (this._config.defaultResponseOptions) { 168 | options = this._config.defaultResponseOptions.merge(options); 169 | } 170 | return new http_1.Response(options); 171 | }; 172 | InMemoryBackendService.prototype._clone = function (data) { 173 | return JSON.parse(JSON.stringify(data)); 174 | }; 175 | /** 176 | * When the `base`="commands", the `collectionName` is the command 177 | * Example URLs: 178 | * commands/resetdb // Reset the "database" to its original state 179 | * commands/config (GET) // Return this service's config object 180 | * commands/config (!GET) // Update the config (e.g. delay) 181 | * 182 | * Usage: 183 | * http.post('commands/resetdb', null); 184 | * http.get('commands/config'); 185 | * http.post('commands/config', '{"delay":1000}'); 186 | */ 187 | InMemoryBackendService.prototype._commands = function (reqInfo) { 188 | var command = reqInfo.collectionName.toLowerCase(); 189 | var method = reqInfo.req.method; 190 | var options; 191 | switch (command) { 192 | case 'resetdb': 193 | this._resetDb(); 194 | options = new http_1.ResponseOptions({ status: http_status_codes_1.STATUS.OK }); 195 | break; 196 | case 'config': 197 | if (method === http_1.RequestMethod.Get) { 198 | options = new http_1.ResponseOptions({ 199 | body: this._clone(this._config), 200 | status: http_status_codes_1.STATUS.OK 201 | }); 202 | } 203 | else { 204 | // Be nice ... any other method is a config update 205 | var body = JSON.parse(reqInfo.req.text() || '{}'); 206 | Object.assign(this._config, body); 207 | options = new http_1.ResponseOptions({ status: http_status_codes_1.STATUS.NO_CONTENT }); 208 | } 209 | break; 210 | default: 211 | options = this._createErrorResponse(http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, "Unknown command \"" + command + "\""); 212 | } 213 | return options; 214 | }; 215 | InMemoryBackendService.prototype._createErrorResponse = function (status, message) { 216 | return new http_1.ResponseOptions({ 217 | body: { 'error': "" + message }, 218 | headers: new http_1.Headers({ 'Content-Type': 'application/json' }), 219 | status: status 220 | }); 221 | }; 222 | InMemoryBackendService.prototype._delete = function (_a) { 223 | var id = _a.id, collection = _a.collection, collectionName = _a.collectionName, headers = _a.headers; 224 | if (!id) { 225 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Missing \"" + collectionName + "\" id"); 226 | } 227 | var exists = this._removeById(collection, id); 228 | return new http_1.ResponseOptions({ 229 | headers: headers, 230 | status: (exists || !this._config.delete404) ? http_status_codes_1.STATUS.NO_CONTENT : http_status_codes_1.STATUS.NOT_FOUND 231 | }); 232 | }; 233 | InMemoryBackendService.prototype._findById = function (collection, id) { 234 | return collection.find(function (item) { return item.id === id; }); 235 | }; 236 | InMemoryBackendService.prototype._genId = function (collection) { 237 | // assumes numeric ids 238 | var maxId = 0; 239 | collection.reduce(function (prev, item) { 240 | maxId = Math.max(maxId, typeof item.id === 'number' ? item.id : maxId); 241 | }, null); 242 | return maxId + 1; 243 | }; 244 | InMemoryBackendService.prototype._get = function (_a) { 245 | var id = _a.id, collection = _a.collection, collectionName = _a.collectionName, headers = _a.headers; 246 | var data = (id) ? this._findById(collection, id) : collection; 247 | if (!data) { 248 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "'" + collectionName + "' with id='" + id + "' not found"); 249 | } 250 | return new http_1.ResponseOptions({ 251 | body: { data: this._clone(data) }, 252 | headers: headers, 253 | status: http_status_codes_1.STATUS.OK 254 | }); 255 | }; 256 | InMemoryBackendService.prototype._getLocation = function (href) { 257 | var l = document.createElement('a'); 258 | l.href = href; 259 | return l; 260 | }; 261 | ; 262 | InMemoryBackendService.prototype._indexOf = function (collection, id) { 263 | return collection.findIndex(function (item) { return item.id === id; }); 264 | }; 265 | // tries to parse id as integer; returns input id if not an integer. 266 | InMemoryBackendService.prototype._parseId = function (id) { 267 | if (!id) { 268 | return null; 269 | } 270 | var idNum = parseInt(id, 10); 271 | return isNaN(idNum) ? id : idNum; 272 | }; 273 | InMemoryBackendService.prototype._parseUrl = function (url) { 274 | try { 275 | var loc = this._getLocation(url); 276 | var drop = this._config.rootPath.length; 277 | var urlRoot = ''; 278 | if (loc.host !== this._config.host) { 279 | // url for a server on a different host! 280 | // assume it's collection is actually here too. 281 | drop = 1; // the leading slash 282 | urlRoot = loc.protocol + '//' + loc.host + '/'; 283 | } 284 | var path = loc.pathname.substring(drop); 285 | var _a = path.split('/'), base = _a[0], collectionName = _a[1], id = _a[2]; 286 | var resourceUrl = urlRoot + base + '/' + collectionName + '/'; 287 | collectionName = collectionName.split('.')[0]; // ignore anything after the '.', e.g., '.json' 288 | return { base: base, id: id, collectionName: collectionName, resourceUrl: resourceUrl }; 289 | } 290 | catch (err) { 291 | var msg = "unable to parse url '" + url + "'; original error: " + err.message; 292 | throw new Error(msg); 293 | } 294 | }; 295 | InMemoryBackendService.prototype._post = function (_a) { 296 | var collection = _a.collection, headers = _a.headers, id = _a.id, req = _a.req, resourceUrl = _a.resourceUrl; 297 | var item = JSON.parse(req.text()); 298 | if (!item.id) { 299 | item.id = id || this._genId(collection); 300 | } 301 | // ignore the request id, if any. Alternatively, 302 | // could reject request if id differs from item.id 303 | id = item.id; 304 | var existingIx = this._indexOf(collection, id); 305 | if (existingIx > -1) { 306 | collection[existingIx] = item; 307 | return new http_1.ResponseOptions({ 308 | headers: headers, 309 | status: http_status_codes_1.STATUS.NO_CONTENT 310 | }); 311 | } 312 | else { 313 | collection.push(item); 314 | headers.set('Location', resourceUrl + '/' + id); 315 | return new http_1.ResponseOptions({ 316 | headers: headers, 317 | body: { data: this._clone(item) }, 318 | status: http_status_codes_1.STATUS.CREATED 319 | }); 320 | } 321 | }; 322 | InMemoryBackendService.prototype._put = function (_a) { 323 | var id = _a.id, collection = _a.collection, collectionName = _a.collectionName, headers = _a.headers, req = _a.req; 324 | var item = JSON.parse(req.text()); 325 | if (!id) { 326 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Missing '" + collectionName + "' id"); 327 | } 328 | if (id !== item.id) { 329 | return this._createErrorResponse(http_status_codes_1.STATUS.BAD_REQUEST, "\"" + collectionName + "\" id does not match item.id"); 330 | } 331 | var existingIx = this._indexOf(collection, id); 332 | if (existingIx > -1) { 333 | collection[existingIx] = item; 334 | return new http_1.ResponseOptions({ 335 | headers: headers, 336 | status: http_status_codes_1.STATUS.NO_CONTENT // successful; no content 337 | }); 338 | } 339 | else { 340 | collection.push(item); 341 | return new http_1.ResponseOptions({ 342 | body: { data: this._clone(item) }, 343 | headers: headers, 344 | status: http_status_codes_1.STATUS.CREATED 345 | }); 346 | } 347 | }; 348 | InMemoryBackendService.prototype._removeById = function (collection, id) { 349 | var ix = this._indexOf(collection, id); 350 | if (ix > -1) { 351 | collection.splice(ix, 1); 352 | return true; 353 | } 354 | return false; 355 | }; 356 | /** 357 | * Reset the "database" to its original state 358 | */ 359 | InMemoryBackendService.prototype._resetDb = function () { 360 | this._db = this._seedData.createDb(); 361 | }; 362 | InMemoryBackendService.prototype._setStatusText = function (options) { 363 | try { 364 | var statusCode = http_status_codes_1.STATUS_CODE_INFO[options.status]; 365 | options['statusText'] = statusCode ? statusCode.text : 'Unknown Status'; 366 | return options; 367 | } 368 | catch (err) { 369 | return new http_1.ResponseOptions({ 370 | status: http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, 371 | statusText: 'Invalid Server Operation' 372 | }); 373 | } 374 | }; 375 | InMemoryBackendService = __decorate([ 376 | __param(0, core_1.Inject(SEED_DATA)), 377 | __param(1, core_1.Inject(InMemoryBackendConfig)), 378 | __param(1, core_1.Optional()), 379 | __metadata('design:paramtypes', [Object, Object]) 380 | ], InMemoryBackendService); 381 | return InMemoryBackendService; 382 | }()); 383 | exports_1("InMemoryBackendService", InMemoryBackendService); 384 | } 385 | } 386 | }); 387 | //# sourceMappingURL=in-memory-backend.service.js.map -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "a2-in-memory-web-api", 3 | "version": "0.1.17", 4 | "description": "An in-memory web api for demos and tests", 5 | "scripts": { 6 | "tsc": "tsc", 7 | "tsc:w": "tsc -w", 8 | "lint": "tslint ./src/in-memory-backend.service.ts -t verbose", 9 | "lite": "lite-server", 10 | "live": "live-server", 11 | "start": "concurrently \"npm run tsc:w\" \"npm run lite\" ", 12 | "test": "karma start karma.conf.js", 13 | "build-and-test": "concurrently \"npm run tsc\" \"npm run test\"", 14 | "http-server": "tsc && http-server", 15 | "typings": "typings" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/wardbell/a2-in-memory-web-api.git" 20 | }, 21 | "keywords": [], 22 | "author": "Ward R. Bell", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/wardbell/a2-in-memory-web-api/issues" 26 | }, 27 | "homepage": "https://github.com/wardbell/a2-in-memory-web-api#readme", 28 | "dependencies": { 29 | "angular2": "2.0.0-beta.17", 30 | "es6-shim": "^0.35.0", 31 | "reflect-metadata": "0.1.2", 32 | "rxjs": "5.0.0-beta.6", 33 | "zone.js": "0.6.12" 34 | }, 35 | "devDependencies": { 36 | "concurrently": "^2.0.0", 37 | "del": "^2.2.0", 38 | "gulp": "^3.9.1", 39 | "gulp-bump": "^2.0.1", 40 | "gulp-load-plugins": "^1.2.2", 41 | "gulp-task-listing": "^1.0.1", 42 | "gulp-util": "^3.0.7", 43 | "http-server": "^0.9.0", 44 | "jasmine-core": "~2.4.1", 45 | "karma": "^0.13.22", 46 | "karma-chrome-launcher": "^0.2.3", 47 | "karma-cli": "^0.1.2", 48 | "karma-jasmine": "^0.3.8", 49 | "lite-server": "^2.2.0", 50 | "live-server": "^1.0.0", 51 | "rimraf": "^2.5.2", 52 | "systemjs": "0.19.26", 53 | "systemjs-builder": "^0.15.15", 54 | "typescript": "^1.8.10", 55 | "typings": "0.8.1", 56 | "yargs": "^4.6.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/core.ts: -------------------------------------------------------------------------------- 1 | export * from './in-memory-backend.service'; 2 | export * from './http-status-codes'; 3 | -------------------------------------------------------------------------------- /src/http-status-codes.ts: -------------------------------------------------------------------------------- 1 | export let STATUS = { 2 | CONTINUE: 100, 3 | SWITCHING_PROTOCOLS: 101, 4 | OK: 200, 5 | CREATED: 201, 6 | ACCEPTED: 202, 7 | NON_AUTHORITATIVE_INFORMATION: 203, 8 | NO_CONTENT: 204, 9 | RESET_CONTENT: 205, 10 | PARTIAL_CONTENT: 206, 11 | MULTIPLE_CHOICES: 300, 12 | MOVED_PERMANTENTLY: 301, 13 | FOUND: 302, 14 | SEE_OTHER: 303, 15 | NOT_MODIFIED: 304, 16 | USE_PROXY: 305, 17 | TEMPORARY_REDIRECT: 307, 18 | BAD_REQUEST: 400, 19 | UNAUTHORIZED: 401, 20 | PAYMENT_REQUIRED: 402, 21 | FORBIDDEN: 403, 22 | NOT_FOUND: 404, 23 | METHOD_NOT_ALLOWED: 405, 24 | NOT_ACCEPTABLE: 406, 25 | PROXY_AUTHENTICATION_REQUIRED: 407, 26 | REQUEST_TIMEOUT: 408, 27 | CONFLICT: 409, 28 | GONE: 410, 29 | LENGTH_REQUIRED: 411, 30 | PRECONDITION_FAILED: 412, 31 | PAYLOAD_TO_LARGE: 413, 32 | URI_TOO_LONG: 414, 33 | UNSUPPORTED_MEDIA_TYPE: 415, 34 | RANGE_NOT_SATISFIABLE: 416, 35 | EXPECTATION_FAILED: 417, 36 | IM_A_TEAPOT: 418, 37 | UPGRADE_REQUIRED: 426, 38 | INTERNAL_SERVER_ERROR: 500, 39 | NOT_IMPLEMENTED: 501, 40 | BAD_GATEWAY: 502, 41 | SERVICE_UNAVAILABLE: 503, 42 | GATEWAY_TIMEOUT: 504, 43 | HTTP_VERSION_NOT_SUPPORTED: 505, 44 | PROCESSING: 102, 45 | MULTI_STATUS: 207, 46 | IM_USED: 226, 47 | PERMANENT_REDIRECT: 308, 48 | UNPROCESSABLE_ENTRY: 422, 49 | LOCKED: 423, 50 | FAILED_DEPENDENCY: 424, 51 | PRECONDITION_REQUIRED: 428, 52 | TOO_MANY_REQUESTS: 429, 53 | REQUEST_HEADER_FIELDS_TOO_LARGE: 431, 54 | UNAVAILABLE_FOR_LEGAL_REASONS: 451, 55 | VARIANT_ALSO_NEGOTIATES: 506, 56 | INSUFFICIENT_STORAGE: 507, 57 | NETWORK_AUTHENTICATION_REQUIRED: 511 58 | }; 59 | 60 | export let STATUS_CODE_INFO = 61 | { 62 | "100": { 63 | "code": 100, 64 | "text": "Continue", 65 | "description": "\"The initial part of a request has been received and has not yet been rejected by the server.\"", 66 | "spec_title": "RFC7231#6.2.1", 67 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.1" 68 | }, 69 | "101": { 70 | "code": 101, 71 | "text": "Switching Protocols", 72 | "description": "\"The server understands and is willing to comply with the client's request, via the Upgrade header field, for a change in the application protocol being used on this connection.\"", 73 | "spec_title": "RFC7231#6.2.2", 74 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.2" 75 | }, 76 | "200": { 77 | "code": 200, 78 | "text": "OK", 79 | "description": "\"The request has succeeded.\"", 80 | "spec_title": "RFC7231#6.3.1", 81 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.1" 82 | }, 83 | "201": { 84 | "code": 201, 85 | "text": "Created", 86 | "description": "\"The request has been fulfilled and has resulted in one or more new resources being created.\"", 87 | "spec_title": "RFC7231#6.3.2", 88 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 89 | }, 90 | "202": { 91 | "code": 202, 92 | "text": "Accepted", 93 | "description": "\"The request has been accepted for processing, but the processing has not been completed.\"", 94 | "spec_title": "RFC7231#6.3.3", 95 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.3" 96 | }, 97 | "203": { 98 | "code": 203, 99 | "text": "Non-Authoritative Information", 100 | "description": "\"The request was successful but the enclosed payload has been modified from that of the origin server's 200 (OK) response by a transforming proxy.\"", 101 | "spec_title": "RFC7231#6.3.4", 102 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.4" 103 | }, 104 | "204": { 105 | "code": 204, 106 | "text": "No Content", 107 | "description": "\"The server has successfully fulfilled the request and that there is no additional content to send in the response payload body.\"", 108 | "spec_title": "RFC7231#6.3.5", 109 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.5" 110 | }, 111 | "205": { 112 | "code": 205, 113 | "text": "Reset Content", 114 | "description": "\"The server has fulfilled the request and desires that the user agent reset the \"document view\", which caused the request to be sent, to its original state as received from the origin server.\"", 115 | "spec_title": "RFC7231#6.3.6", 116 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.6" 117 | }, 118 | "206": { 119 | "code": 206, 120 | "text": "Partial Content", 121 | "description": "\"The server is successfully fulfilling a range request for the target resource by transferring one or more parts of the selected representation that correspond to the satisfiable ranges found in the requests's Range header field.\"", 122 | "spec_title": "RFC7233#4.1", 123 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.1" 124 | }, 125 | "300": { 126 | "code": 300, 127 | "text": "Multiple Choices", 128 | "description": "\"The target resource has more than one representation, each with its own more specific identifier, and information about the alternatives is being provided so that the user (or user agent) can select a preferred representation by redirecting its request to one or more of those identifiers.\"", 129 | "spec_title": "RFC7231#6.4.1", 130 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.1" 131 | }, 132 | "301": { 133 | "code": 301, 134 | "text": "Moved Permanently", 135 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs.\"", 136 | "spec_title": "RFC7231#6.4.2", 137 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.2" 138 | }, 139 | "302": { 140 | "code": 302, 141 | "text": "Found", 142 | "description": "\"The target resource resides temporarily under a different URI.\"", 143 | "spec_title": "RFC7231#6.4.3", 144 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.3" 145 | }, 146 | "303": { 147 | "code": 303, 148 | "text": "See Other", 149 | "description": "\"The server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field, that is intended to provide an indirect response to the original request.\"", 150 | "spec_title": "RFC7231#6.4.4", 151 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.4" 152 | }, 153 | "304": { 154 | "code": 304, 155 | "text": "Not Modified", 156 | "description": "\"A conditional GET request has been received and would have resulted in a 200 (OK) response if it were not for the fact that the condition has evaluated to false.\"", 157 | "spec_title": "RFC7232#4.1", 158 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.1" 159 | }, 160 | "305": { 161 | "code": 305, 162 | "text": "Use Proxy", 163 | "description": "*deprecated*", 164 | "spec_title": "RFC7231#6.4.5", 165 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.5" 166 | }, 167 | "307": { 168 | "code": 307, 169 | "text": "Temporary Redirect", 170 | "description": "\"The target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI.\"", 171 | "spec_title": "RFC7231#6.4.7", 172 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.7" 173 | }, 174 | "400": { 175 | "code": 400, 176 | "text": "Bad Request", 177 | "description": "\"The server cannot or will not process the request because the received syntax is invalid, nonsensical, or exceeds some limitation on what the server is willing to process.\"", 178 | "spec_title": "RFC7231#6.5.1", 179 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.1" 180 | }, 181 | "401": { 182 | "code": 401, 183 | "text": "Unauthorized", 184 | "description": "\"The request has not been applied because it lacks valid authentication credentials for the target resource.\"", 185 | "spec_title": "RFC7235#6.3.1", 186 | "spec_href": "http://tools.ietf.org/html/rfc7235#section-3.1" 187 | }, 188 | "402": { 189 | "code": 402, 190 | "text": "Payment Required", 191 | "description": "*reserved*", 192 | "spec_title": "RFC7231#6.5.2", 193 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.2" 194 | }, 195 | "403": { 196 | "code": 403, 197 | "text": "Forbidden", 198 | "description": "\"The server understood the request but refuses to authorize it.\"", 199 | "spec_title": "RFC7231#6.5.3", 200 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.3" 201 | }, 202 | "404": { 203 | "code": 404, 204 | "text": "Not Found", 205 | "description": "\"The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.\"", 206 | "spec_title": "RFC7231#6.5.4", 207 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.4" 208 | }, 209 | "405": { 210 | "code": 405, 211 | "text": "Method Not Allowed", 212 | "description": "\"The method specified in the request-line is known by the origin server but not supported by the target resource.\"", 213 | "spec_title": "RFC7231#6.5.5", 214 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.5" 215 | }, 216 | "406": { 217 | "code": 406, 218 | "text": "Not Acceptable", 219 | "description": "\"The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.\"", 220 | "spec_title": "RFC7231#6.5.6", 221 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.6" 222 | }, 223 | "407": { 224 | "code": 407, 225 | "text": "Proxy Authentication Required", 226 | "description": "\"The client needs to authenticate itself in order to use a proxy.\"", 227 | "spec_title": "RFC7231#6.3.2", 228 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 229 | }, 230 | "408": { 231 | "code": 408, 232 | "text": "Request Timeout", 233 | "description": "\"The server did not receive a complete request message within the time that it was prepared to wait.\"", 234 | "spec_title": "RFC7231#6.5.7", 235 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.7" 236 | }, 237 | "409": { 238 | "code": 409, 239 | "text": "Conflict", 240 | "description": "\"The request could not be completed due to a conflict with the current state of the resource.\"", 241 | "spec_title": "RFC7231#6.5.8", 242 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.8" 243 | }, 244 | "410": { 245 | "code": 410, 246 | "text": "Gone", 247 | "description": "\"Access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.\"", 248 | "spec_title": "RFC7231#6.5.9", 249 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.9" 250 | }, 251 | "411": { 252 | "code": 411, 253 | "text": "Length Required", 254 | "description": "\"The server refuses to accept the request without a defined Content-Length.\"", 255 | "spec_title": "RFC7231#6.5.10", 256 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.10" 257 | }, 258 | "412": { 259 | "code": 412, 260 | "text": "Precondition Failed", 261 | "description": "\"One or more preconditions given in the request header fields evaluated to false when tested on the server.\"", 262 | "spec_title": "RFC7232#4.2", 263 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.2" 264 | }, 265 | "413": { 266 | "code": 413, 267 | "text": "Payload Too Large", 268 | "description": "\"The server is refusing to process a request because the request payload is larger than the server is willing or able to process.\"", 269 | "spec_title": "RFC7231#6.5.11", 270 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.11" 271 | }, 272 | "414": { 273 | "code": 414, 274 | "text": "URI Too Long", 275 | "description": "\"The server is refusing to service the request because the request-target is longer than the server is willing to interpret.\"", 276 | "spec_title": "RFC7231#6.5.12", 277 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.12" 278 | }, 279 | "415": { 280 | "code": 415, 281 | "text": "Unsupported Media Type", 282 | "description": "\"The origin server is refusing to service the request because the payload is in a format not supported by the target resource for this method.\"", 283 | "spec_title": "RFC7231#6.5.13", 284 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.13" 285 | }, 286 | "416": { 287 | "code": 416, 288 | "text": "Range Not Satisfiable", 289 | "description": "\"None of the ranges in the request's Range header field overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges.\"", 290 | "spec_title": "RFC7233#4.4", 291 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.4" 292 | }, 293 | "417": { 294 | "code": 417, 295 | "text": "Expectation Failed", 296 | "description": "\"The expectation given in the request's Expect header field could not be met by at least one of the inbound servers.\"", 297 | "spec_title": "RFC7231#6.5.14", 298 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.14" 299 | }, 300 | "418": { 301 | "code": 418, 302 | "text": "I'm a teapot", 303 | "description": "\"1988 April Fools Joke. Returned by tea pots requested to brew coffee.\"", 304 | "spec_title": "RFC 2324", 305 | "spec_href": "https://tools.ietf.org/html/rfc2324" 306 | }, 307 | "426": { 308 | "code": 426, 309 | "text": "Upgrade Required", 310 | "description": "\"The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol.\"", 311 | "spec_title": "RFC7231#6.5.15", 312 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.15" 313 | }, 314 | "500": { 315 | "code": 500, 316 | "text": "Internal Server Error", 317 | "description": "\"The server encountered an unexpected condition that prevented it from fulfilling the request.\"", 318 | "spec_title": "RFC7231#6.6.1", 319 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.1" 320 | }, 321 | "501": { 322 | "code": 501, 323 | "text": "Not Implemented", 324 | "description": "\"The server does not support the functionality required to fulfill the request.\"", 325 | "spec_title": "RFC7231#6.6.2", 326 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.2" 327 | }, 328 | "502": { 329 | "code": 502, 330 | "text": "Bad Gateway", 331 | "description": "\"The server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.\"", 332 | "spec_title": "RFC7231#6.6.3", 333 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.3" 334 | }, 335 | "503": { 336 | "code": 503, 337 | "text": "Service Unavailable", 338 | "description": "\"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.\"", 339 | "spec_title": "RFC7231#6.6.4", 340 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.4" 341 | }, 342 | "504": { 343 | "code": 504, 344 | "text": "Gateway Time-out", 345 | "description": "\"The server, while acting as a gateway or proxy, did not receive a timely response from an upstream server it needed to access in order to complete the request.\"", 346 | "spec_title": "RFC7231#6.6.5", 347 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.5" 348 | }, 349 | "505": { 350 | "code": 505, 351 | "text": "HTTP Version Not Supported", 352 | "description": "\"The server does not support, or refuses to support, the protocol version that was used in the request message.\"", 353 | "spec_title": "RFC7231#6.6.6", 354 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.6" 355 | }, 356 | "102": { 357 | "code": 102, 358 | "text": "Processing", 359 | "description": "\"An interim response to inform the client that the server has accepted the complete request, but has not yet completed it.\"", 360 | "spec_title": "RFC5218#10.1", 361 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.1" 362 | }, 363 | "207": { 364 | "code": 207, 365 | "text": "Multi-Status", 366 | "description": "\"Status for multiple independent operations.\"", 367 | "spec_title": "RFC5218#10.2", 368 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.2" 369 | }, 370 | "226": { 371 | "code": 226, 372 | "text": "IM Used", 373 | "description": "\"The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance.\"", 374 | "spec_title": "RFC3229#10.4.1", 375 | "spec_href": "http://tools.ietf.org/html/rfc3229#section-10.4.1" 376 | }, 377 | "308": { 378 | "code": 308, 379 | "text": "Permanent Redirect", 380 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. [...] This status code is similar to 301 Moved Permanently (Section 7.3.2 of rfc7231), except that it does not allow rewriting the request method from POST to GET.\"", 381 | "spec_title": "RFC7238", 382 | "spec_href": "http://tools.ietf.org/html/rfc7238" 383 | }, 384 | "422": { 385 | "code": 422, 386 | "text": "Unprocessable Entity", 387 | "description": "\"The server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions.\"", 388 | "spec_title": "RFC5218#10.3", 389 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.3" 390 | }, 391 | "423": { 392 | "code": 423, 393 | "text": "Locked", 394 | "description": "\"The source or destination resource of a method is locked.\"", 395 | "spec_title": "RFC5218#10.4", 396 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.4" 397 | }, 398 | "424": { 399 | "code": 424, 400 | "text": "Failed Dependency", 401 | "description": "\"The method could not be performed on the resource because the requested action depended on another action and that action failed.\"", 402 | "spec_title": "RFC5218#10.5", 403 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.5" 404 | }, 405 | "428": { 406 | "code": 428, 407 | "text": "Precondition Required", 408 | "description": "\"The origin server requires the request to be conditional.\"", 409 | "spec_title": "RFC6585#3", 410 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-3" 411 | }, 412 | "429": { 413 | "code": 429, 414 | "text": "Too Many Requests", 415 | "description": "\"The user has sent too many requests in a given amount of time (\"rate limiting\").\"", 416 | "spec_title": "RFC6585#4", 417 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-4" 418 | }, 419 | "431": { 420 | "code": 431, 421 | "text": "Request Header Fields Too Large", 422 | "description": "\"The server is unwilling to process the request because its header fields are too large.\"", 423 | "spec_title": "RFC6585#5", 424 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-5" 425 | }, 426 | "451": { 427 | "code": 451, 428 | "text": "Unavailable For Legal Reasons", 429 | "description": "\"The server is denying access to the resource in response to a legal demand.\"", 430 | "spec_title": "draft-ietf-httpbis-legally-restricted-status", 431 | "spec_href": "http://tools.ietf.org/html/draft-ietf-httpbis-legally-restricted-status" 432 | }, 433 | "506": { 434 | "code": 506, 435 | "text": "Variant Also Negotiates", 436 | "description": "\"The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.\"", 437 | "spec_title": "RFC2295#8.1", 438 | "spec_href": "http://tools.ietf.org/html/rfc2295#section-8.1" 439 | }, 440 | "507": { 441 | "code": 507, 442 | "text": "Insufficient Storage", 443 | "description": "\The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request.\"", 444 | "spec_title": "RFC5218#10.6", 445 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.6" 446 | }, 447 | "511": { 448 | "code": 511, 449 | "text": "Network Authentication Required", 450 | "description": "\"The client needs to authenticate to gain network access.\"", 451 | "spec_title": "RFC6585#6", 452 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-6" 453 | } 454 | }; 455 | -------------------------------------------------------------------------------- /src/in-memory-backend.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, OpaqueToken, Optional } from 'angular2/core'; 2 | import { BaseResponseOptions, Headers, Request, RequestMethod, Response, ResponseOptions } from 'angular2/http'; 3 | import { Observable } from 'rxjs/Observable'; 4 | import { Observer } from 'rxjs/Observer'; 5 | import 'rxjs/add/operator/delay'; 6 | 7 | import { STATUS, STATUS_CODE_INFO } from './http-status-codes'; 8 | 9 | /** 10 | * Seed data for in-memory database 11 | * Must implement InMemoryDbService. 12 | */ 13 | export const SEED_DATA = new OpaqueToken('seedData'); 14 | 15 | /** 16 | * Interface for a class that creates an in-memory database 17 | * Safe for consuming service to morph arrays and objects. 18 | */ 19 | export interface InMemoryDbService { 20 | /** 21 | * Creates "database" object hash whose keys are collection names 22 | * and whose values are arrays of the collection objects. 23 | * 24 | * It must be safe to call again and should return new arrays with new objects. 25 | * This condition allows InMemoryBackendService to morph the arrays and objects 26 | * without touching the original source data. 27 | */ 28 | createDb(): {}; 29 | } 30 | 31 | /** 32 | * Interface for InMemoryBackend configuration options 33 | */ 34 | export interface InMemoryBackendConfigArgs { 35 | /** 36 | * default response options 37 | */ 38 | defaultResponseOptions?: ResponseOptions; 39 | /** 40 | * delay (in ms) to simulate latency 41 | */ 42 | delay?: number; 43 | /** 44 | * false (default) if ok when object-to-delete not found; else 404 45 | */ 46 | delete404?: boolean; 47 | /** 48 | * host for this service 49 | */ 50 | host?: string; 51 | /** 52 | * root path before any API call 53 | */ 54 | rootPath?: string; 55 | } 56 | 57 | /** 58 | * InMemoryBackendService configuration options 59 | * Usage: 60 | * provide(InMemoryBackendConfig, {useValue: {delay:600}}), 61 | */ 62 | export class InMemoryBackendConfig implements InMemoryBackendConfigArgs { 63 | constructor(config: InMemoryBackendConfigArgs = {}) { 64 | Object.assign(this, { 65 | defaultResponseOptions: new BaseResponseOptions(), 66 | delay: 500, 67 | delete404: false 68 | }, config); 69 | } 70 | } 71 | 72 | /** 73 | * Interface for object w/ info about the current request url 74 | * extracted from an Http Request 75 | */ 76 | export interface ReqInfo { 77 | req: Request; 78 | base: string; 79 | collection: any[]; 80 | collectionName: string; 81 | headers: Headers; 82 | id: any; 83 | resourceUrl: string; 84 | } 85 | 86 | export const isSuccess = (status: number): boolean => (status >= 200 && status < 300); 87 | 88 | /** 89 | * Simulate the behavior of a RESTy web api 90 | * backed by the simple in-memory data store provided by the injected InMemoryDataService service. 91 | * Conforms mostly to behavior described here: 92 | * http://www.restapitutorial.com/lessons/httpmethods.html 93 | * 94 | * ### Usage 95 | * 96 | * Create InMemoryDataService class the implements IInMemoryDataService. 97 | * Register both this service and the seed data as in: 98 | * ``` 99 | * // other imports 100 | * import { HTTP_PROVIDERS, XHRBackend } from 'angular2/http'; 101 | * import { InMemoryBackendConfig, InMemoryBackendService, SEED_DATA } from '../in-memory-backend/in-memory-backend.service'; 102 | * import { InMemoryStoryService } from '../api/in-memory-story.service'; 103 | * 104 | * @Component({ 105 | * selector: ..., 106 | * templateUrl: ..., 107 | * providers: [ 108 | * HTTP_PROVIDERS, 109 | * provide(XHRBackend, { useClass: InMemoryBackendService }), 110 | * provide(SEED_DATA, { useClass: InMemoryStoryService }), 111 | * provide(InMemoryBackendConfig, { useValue: { delay: 600 } }), 112 | * ] 113 | * }) 114 | * export class AppComponent { ... } 115 | * ``` 116 | */ 117 | 118 | export class InMemoryBackendService { 119 | 120 | protected _config: InMemoryBackendConfigArgs = new InMemoryBackendConfig(); 121 | protected _db: {}; 122 | 123 | constructor( 124 | @Inject(SEED_DATA) private _seedData: InMemoryDbService, 125 | @Inject(InMemoryBackendConfig) @Optional() config: InMemoryBackendConfigArgs) { 126 | this._resetDb(); 127 | 128 | let loc = this._getLocation('./'); 129 | this._config.host = loc.host; 130 | this._config.rootPath = loc.pathname; 131 | Object.assign(this._config, config); 132 | } 133 | 134 | createConnection(req: Request) { 135 | let res = this._handleRequest(req); 136 | 137 | let response = new Observable((responseObserver: Observer) => { 138 | if (isSuccess(res.status)) { 139 | responseObserver.next(res); 140 | responseObserver.complete(); 141 | } else { 142 | responseObserver.error(res); 143 | } 144 | return () => { }; // unsubscribe function 145 | }); 146 | 147 | response = response.delay(this._config.delay || 500); 148 | return { response }; 149 | } 150 | 151 | //// protected ///// 152 | 153 | /** 154 | * Process Request and return an Http Response object 155 | * in the manner of a RESTy web api. 156 | * 157 | * Expect URI pattern in the form :base/:collectionName/:id? 158 | * Examples: 159 | * api/characters 160 | * api/characters/42 161 | * api/characters.json/42 // ignores the ".json" 162 | * commands/resetDb // resets the "database" 163 | */ 164 | protected _handleRequest(req: Request) { 165 | let {base, collectionName, id, resourceUrl} = this._parseUrl(req.url); 166 | 167 | let reqInfo: ReqInfo = { 168 | req: req, 169 | base: base, 170 | collection: this._db[collectionName], 171 | collectionName: collectionName, 172 | headers: new Headers({ 'Content-Type': 'application/json' }), 173 | id: this._parseId(id), 174 | resourceUrl: resourceUrl 175 | }; 176 | 177 | let options: ResponseOptions; 178 | 179 | try { 180 | if ('commands' === reqInfo.base.toLowerCase()) { 181 | options = this._commands(reqInfo); 182 | 183 | } else if (reqInfo.collection) { 184 | switch (req.method) { 185 | case RequestMethod.Get: 186 | options = this._get(reqInfo); 187 | break; 188 | case RequestMethod.Post: 189 | options = this._post(reqInfo); 190 | break; 191 | case RequestMethod.Put: 192 | options = this._put(reqInfo); 193 | break; 194 | case RequestMethod.Delete: 195 | options = this._delete(reqInfo); 196 | break; 197 | default: 198 | options = this._createErrorResponse(STATUS.METHOD_NOT_ALLOWED, 'Method not allowed'); 199 | break; 200 | } 201 | 202 | } else { 203 | options = this._createErrorResponse(STATUS.NOT_FOUND, `Collection '${collectionName}' not found`); 204 | } 205 | 206 | } catch (error) { 207 | let err = error.message || error; 208 | options = this._createErrorResponse(STATUS.INTERNAL_SERVER_ERROR, `${err}`); 209 | } 210 | 211 | options = this._setStatusText(options); 212 | if (this._config.defaultResponseOptions) { 213 | options = this._config.defaultResponseOptions.merge(options); 214 | } 215 | 216 | return new Response(options); 217 | } 218 | 219 | protected _clone(data: any) { 220 | return JSON.parse(JSON.stringify(data)); 221 | } 222 | 223 | /** 224 | * When the `base`="commands", the `collectionName` is the command 225 | * Example URLs: 226 | * commands/resetdb // Reset the "database" to its original state 227 | * commands/config (GET) // Return this service's config object 228 | * commands/config (!GET) // Update the config (e.g. delay) 229 | * 230 | * Usage: 231 | * http.post('commands/resetdb', null); 232 | * http.get('commands/config'); 233 | * http.post('commands/config', '{"delay":1000}'); 234 | */ 235 | protected _commands(reqInfo: ReqInfo) { 236 | let command = reqInfo.collectionName.toLowerCase(); 237 | let method = reqInfo.req.method; 238 | let options: ResponseOptions; 239 | 240 | switch (command) { 241 | case 'resetdb': 242 | this._resetDb(); 243 | options = new ResponseOptions({ status: STATUS.OK }); 244 | break; 245 | case 'config': 246 | if (method === RequestMethod.Get) { 247 | options = new ResponseOptions({ 248 | body: this._clone(this._config), 249 | status: STATUS.OK 250 | }); 251 | } else { 252 | // Be nice ... any other method is a config update 253 | let body = JSON.parse(reqInfo.req.text() || '{}'); 254 | Object.assign(this._config, body); 255 | options = new ResponseOptions({ status: STATUS.NO_CONTENT }); 256 | } 257 | break; 258 | default: 259 | options = this._createErrorResponse( 260 | STATUS.INTERNAL_SERVER_ERROR, `Unknown command "${command}"`); 261 | } 262 | return options; 263 | } 264 | 265 | protected _createErrorResponse(status: number, message: string) { 266 | return new ResponseOptions({ 267 | body: { 'error': `${message}` }, 268 | headers: new Headers({ 'Content-Type': 'application/json' }), 269 | status: status 270 | }); 271 | } 272 | 273 | protected _delete({id, collection, collectionName, headers /*, req */}: ReqInfo) { 274 | if (!id) { 275 | return this._createErrorResponse(STATUS.NOT_FOUND, `Missing "${collectionName}" id`); 276 | } 277 | let exists = this._removeById(collection, id); 278 | return new ResponseOptions({ 279 | headers: headers, 280 | status: (exists || !this._config.delete404) ? STATUS.NO_CONTENT : STATUS.NOT_FOUND 281 | }); 282 | } 283 | 284 | protected _findById(collection: any[], id: number) { 285 | return collection.find((item: any) => item.id === id); 286 | } 287 | 288 | protected _genId(collection: any): any { 289 | // assumes numeric ids 290 | let maxId = 0; 291 | collection.reduce((prev: any, item: any) => { 292 | maxId = Math.max(maxId, typeof item.id === 'number' ? item.id : maxId); 293 | }, null); 294 | return maxId + 1; 295 | } 296 | 297 | protected _get({id, collection, collectionName, headers}: ReqInfo) { 298 | let data = (id) ? this._findById(collection, id) : collection; 299 | if (!data) { 300 | return this._createErrorResponse(STATUS.NOT_FOUND, 301 | `'${collectionName}' with id='${id}' not found`); 302 | } 303 | return new ResponseOptions({ 304 | body: { data: this._clone(data) }, 305 | headers: headers, 306 | status: STATUS.OK 307 | }); 308 | } 309 | 310 | protected _getLocation(href: string) { 311 | let l = document.createElement('a'); 312 | l.href = href; 313 | return l; 314 | }; 315 | 316 | protected _indexOf(collection: any[], id: number) { 317 | return collection.findIndex((item: any) => item.id === id); 318 | } 319 | 320 | // tries to parse id as integer; returns input id if not an integer. 321 | protected _parseId(id: string): any { 322 | if (!id) { return null; } 323 | let idNum = parseInt(id, 10); 324 | return isNaN(idNum) ? id : idNum; 325 | } 326 | 327 | protected _parseUrl(url: string) { 328 | try { 329 | let loc = this._getLocation(url); 330 | let drop = this._config.rootPath.length; 331 | let urlRoot = ''; 332 | if (loc.host !== this._config.host) { 333 | // url for a server on a different host! 334 | // assume it's collection is actually here too. 335 | drop = 1; // the leading slash 336 | urlRoot = loc.protocol + '//' + loc.host + '/'; 337 | } 338 | let path = loc.pathname.substring(drop); 339 | let [base, collectionName, id] = path.split('/'); 340 | let resourceUrl = urlRoot + base + '/' + collectionName + '/'; 341 | [collectionName] = collectionName.split('.'); // ignore anything after the '.', e.g., '.json' 342 | return { base, id, collectionName, resourceUrl }; 343 | } catch (err) { 344 | let msg = `unable to parse url '${url}'; original error: ${err.message}`; 345 | throw new Error(msg); 346 | } 347 | } 348 | 349 | protected _post({collection, /* collectionName, */ headers, id, req, resourceUrl}: ReqInfo) { 350 | let item = JSON.parse(req.text()); 351 | if (!item.id) { 352 | item.id = id || this._genId(collection); 353 | } 354 | // ignore the request id, if any. Alternatively, 355 | // could reject request if id differs from item.id 356 | id = item.id; 357 | let existingIx = this._indexOf(collection, id); 358 | if (existingIx > -1) { 359 | collection[existingIx] = item; 360 | return new ResponseOptions({ 361 | headers: headers, 362 | status: STATUS.NO_CONTENT 363 | }); 364 | } else { 365 | collection.push(item); 366 | headers.set('Location', resourceUrl + '/' + id); 367 | return new ResponseOptions({ 368 | headers: headers, 369 | body: { data: this._clone(item) }, 370 | status: STATUS.CREATED 371 | }); 372 | } 373 | } 374 | 375 | protected _put({id, collection, collectionName, headers, req}: ReqInfo) { 376 | let item = JSON.parse(req.text()); 377 | if (!id) { 378 | return this._createErrorResponse(STATUS.NOT_FOUND, `Missing '${collectionName}' id`); 379 | } 380 | if (id !== item.id) { 381 | return this._createErrorResponse(STATUS.BAD_REQUEST, 382 | `"${collectionName}" id does not match item.id`); 383 | } 384 | let existingIx = this._indexOf(collection, id); 385 | if (existingIx > -1) { 386 | collection[existingIx] = item; 387 | return new ResponseOptions({ 388 | headers: headers, 389 | status: STATUS.NO_CONTENT // successful; no content 390 | }); 391 | } else { 392 | collection.push(item); 393 | return new ResponseOptions({ 394 | body: { data: this._clone(item) }, 395 | headers: headers, 396 | status: STATUS.CREATED 397 | }); 398 | } 399 | } 400 | 401 | protected _removeById(collection: any[], id: number) { 402 | let ix = this._indexOf(collection, id); 403 | if (ix > -1) { 404 | collection.splice(ix, 1); 405 | return true; 406 | } 407 | return false; 408 | } 409 | 410 | /** 411 | * Reset the "database" to its original state 412 | */ 413 | protected _resetDb() { 414 | this._db = this._seedData.createDb(); 415 | } 416 | 417 | protected _setStatusText(options: ResponseOptions) { 418 | try { 419 | let statusCode = STATUS_CODE_INFO[options.status]; 420 | options['statusText'] = statusCode ? statusCode.text : 'Unknown Status'; 421 | return options; 422 | } catch (err) { 423 | return new ResponseOptions({ 424 | status: STATUS.INTERNAL_SERVER_ERROR, 425 | statusText: 'Invalid Server Operation' 426 | }); 427 | } 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "system", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "outDir": "./a2-in-memory-web-api", 8 | "declaration": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "removeComments": false, 12 | "noImplicitAny": true, 13 | "suppressImplicitAnyIndexErrors": true 14 | }, 15 | "exclude": [ 16 | "node_modules", 17 | "a2-in-memory-web-api", 18 | "typings/main", 19 | "typings/main.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | "static-before-instance", 25 | "variables-before-functions" 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [ 30 | true, 31 | "debug", 32 | "info", 33 | "time", 34 | "timeEnd", 35 | "trace" 36 | ], 37 | "no-construct": true, 38 | "no-debugger": true, 39 | "no-duplicate-key": true, 40 | "no-duplicate-variable": true, 41 | "no-empty": false, 42 | "no-eval": true, 43 | "no-inferrable-types": true, 44 | "no-shadowed-variable": true, 45 | "no-string-literal": false, 46 | "no-switch-case-fall-through": true, 47 | "no-trailing-whitespace": true, 48 | "no-unused-expression": true, 49 | "no-unused-variable": true, 50 | "no-unreachable": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": false, 54 | "one-line": [ 55 | true, 56 | "check-open-brace", 57 | "check-catch", 58 | "check-else", 59 | "check-whitespace" 60 | ], 61 | "quotemark": [ 62 | true, 63 | "single" 64 | ], 65 | "radix": true, 66 | "semicolon": [ 67 | "always" 68 | ], 69 | "triple-equals": [ 70 | true, 71 | "allow-null-check" 72 | ], 73 | "typedef-whitespace": [ 74 | true, 75 | { 76 | "call-signature": "nospace", 77 | "index-signature": "nospace", 78 | "parameter": "nospace", 79 | "property-declaration": "nospace", 80 | "variable-declaration": "nospace" 81 | } 82 | ], 83 | "variable-name": false, 84 | "whitespace": [ 85 | true, 86 | "check-branch", 87 | "check-decl", 88 | "check-operator", 89 | "check-separator", 90 | "check-type" 91 | ] 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientDependencies": { 3 | "es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /web-api.js: -------------------------------------------------------------------------------- 1 | System.register("a2-in-memory-web-api/in-memory-backend.service", ["angular2/core", "angular2/http", "rxjs/Observable", "rxjs/add/operator/delay", "./http-status-codes"], function(exports_1, context_1) { 2 | "use strict"; 3 | var __moduleName = context_1 && context_1.id; 4 | var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) { 5 | var c = arguments.length, 6 | r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, 7 | d; 8 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") 9 | r = Reflect.decorate(decorators, target, key, desc); 10 | else 11 | for (var i = decorators.length - 1; i >= 0; i--) 12 | if (d = decorators[i]) 13 | r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 14 | return c > 3 && r && Object.defineProperty(target, key, r), r; 15 | }; 16 | var __metadata = (this && this.__metadata) || function(k, v) { 17 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") 18 | return Reflect.metadata(k, v); 19 | }; 20 | var __param = (this && this.__param) || function(paramIndex, decorator) { 21 | return function(target, key) { 22 | decorator(target, key, paramIndex); 23 | }; 24 | }; 25 | var core_1, 26 | http_1, 27 | Observable_1, 28 | http_status_codes_1; 29 | var SEED_DATA, 30 | InMemoryBackendConfig, 31 | isSuccess, 32 | InMemoryBackendService; 33 | return { 34 | setters: [function(core_1_1) { 35 | core_1 = core_1_1; 36 | }, function(http_1_1) { 37 | http_1 = http_1_1; 38 | }, function(Observable_1_1) { 39 | Observable_1 = Observable_1_1; 40 | }, function(_1) {}, function(http_status_codes_1_1) { 41 | http_status_codes_1 = http_status_codes_1_1; 42 | }], 43 | execute: function() { 44 | exports_1("SEED_DATA", SEED_DATA = new core_1.OpaqueToken('seedData')); 45 | InMemoryBackendConfig = (function() { 46 | function InMemoryBackendConfig(config) { 47 | if (config === void 0) { 48 | config = {}; 49 | } 50 | Object.assign(this, { 51 | defaultResponseOptions: new http_1.BaseResponseOptions(), 52 | delay: 500, 53 | delete404: false 54 | }, config); 55 | } 56 | return InMemoryBackendConfig; 57 | }()); 58 | exports_1("InMemoryBackendConfig", InMemoryBackendConfig); 59 | exports_1("isSuccess", isSuccess = function(status) { 60 | return (status >= 200 && status < 300); 61 | }); 62 | InMemoryBackendService = (function() { 63 | function InMemoryBackendService(_seedData, config) { 64 | this._seedData = _seedData; 65 | this._config = new InMemoryBackendConfig(); 66 | this._resetDb(); 67 | var loc = this._getLocation('./'); 68 | this._config.host = loc.host; 69 | this._config.rootPath = loc.pathname; 70 | Object.assign(this._config, config); 71 | } 72 | InMemoryBackendService.prototype.createConnection = function(req) { 73 | var res = this._handleRequest(req); 74 | var response = new Observable_1.Observable(function(responseObserver) { 75 | if (isSuccess(res.status)) { 76 | responseObserver.next(res); 77 | responseObserver.complete(); 78 | } else { 79 | responseObserver.error(res); 80 | } 81 | return function() {}; 82 | }); 83 | response = response.delay(this._config.delay || 500); 84 | return {response: response}; 85 | }; 86 | InMemoryBackendService.prototype._handleRequest = function(req) { 87 | var _a = this._parseUrl(req.url), 88 | base = _a.base, 89 | collectionName = _a.collectionName, 90 | id = _a.id, 91 | resourceUrl = _a.resourceUrl; 92 | var reqInfo = { 93 | req: req, 94 | base: base, 95 | collection: this._db[collectionName], 96 | collectionName: collectionName, 97 | headers: new http_1.Headers({'Content-Type': 'application/json'}), 98 | id: this._parseId(id), 99 | resourceUrl: resourceUrl 100 | }; 101 | var options; 102 | try { 103 | if ('commands' === reqInfo.base.toLowerCase()) { 104 | options = this._commands(reqInfo); 105 | } else if (reqInfo.collection) { 106 | switch (req.method) { 107 | case http_1.RequestMethod.Get: 108 | options = this._get(reqInfo); 109 | break; 110 | case http_1.RequestMethod.Post: 111 | options = this._post(reqInfo); 112 | break; 113 | case http_1.RequestMethod.Put: 114 | options = this._put(reqInfo); 115 | break; 116 | case http_1.RequestMethod.Delete: 117 | options = this._delete(reqInfo); 118 | break; 119 | default: 120 | options = this._createErrorResponse(http_status_codes_1.STATUS.METHOD_NOT_ALLOWED, 'Method not allowed'); 121 | break; 122 | } 123 | } else { 124 | options = this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Collection '" + collectionName + "' not found"); 125 | } 126 | } catch (error) { 127 | var err = error.message || error; 128 | options = this._createErrorResponse(http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, "" + err); 129 | } 130 | options = this._setStatusText(options); 131 | if (this._config.defaultResponseOptions) { 132 | options = this._config.defaultResponseOptions.merge(options); 133 | } 134 | return new http_1.Response(options); 135 | }; 136 | InMemoryBackendService.prototype._clone = function(data) { 137 | return JSON.parse(JSON.stringify(data)); 138 | }; 139 | InMemoryBackendService.prototype._commands = function(reqInfo) { 140 | var command = reqInfo.collectionName.toLowerCase(); 141 | var method = reqInfo.req.method; 142 | var options; 143 | switch (command) { 144 | case 'resetdb': 145 | this._resetDb(); 146 | options = new http_1.ResponseOptions({status: http_status_codes_1.STATUS.OK}); 147 | break; 148 | case 'config': 149 | if (method === http_1.RequestMethod.Get) { 150 | options = new http_1.ResponseOptions({ 151 | body: this._clone(this._config), 152 | status: http_status_codes_1.STATUS.OK 153 | }); 154 | } else { 155 | var body = JSON.parse(reqInfo.req.text() || '{}'); 156 | Object.assign(this._config, body); 157 | options = new http_1.ResponseOptions({status: http_status_codes_1.STATUS.NO_CONTENT}); 158 | } 159 | break; 160 | default: 161 | options = this._createErrorResponse(http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, "Unknown command \"" + command + "\""); 162 | } 163 | return options; 164 | }; 165 | InMemoryBackendService.prototype._createErrorResponse = function(status, message) { 166 | return new http_1.ResponseOptions({ 167 | body: {'error': "" + message}, 168 | headers: new http_1.Headers({'Content-Type': 'application/json'}), 169 | status: status 170 | }); 171 | }; 172 | InMemoryBackendService.prototype._delete = function(_a) { 173 | var id = _a.id, 174 | collection = _a.collection, 175 | collectionName = _a.collectionName, 176 | headers = _a.headers; 177 | if (!id) { 178 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Missing \"" + collectionName + "\" id"); 179 | } 180 | var exists = this._removeById(collection, id); 181 | return new http_1.ResponseOptions({ 182 | headers: headers, 183 | status: (exists || !this._config.delete404) ? http_status_codes_1.STATUS.NO_CONTENT : http_status_codes_1.STATUS.NOT_FOUND 184 | }); 185 | }; 186 | InMemoryBackendService.prototype._findById = function(collection, id) { 187 | return collection.find(function(item) { 188 | return item.id === id; 189 | }); 190 | }; 191 | InMemoryBackendService.prototype._genId = function(collection) { 192 | var maxId = 0; 193 | collection.reduce(function(prev, item) { 194 | maxId = Math.max(maxId, typeof item.id === 'number' ? item.id : maxId); 195 | }, null); 196 | return maxId + 1; 197 | }; 198 | InMemoryBackendService.prototype._get = function(_a) { 199 | var id = _a.id, 200 | collection = _a.collection, 201 | collectionName = _a.collectionName, 202 | headers = _a.headers; 203 | var data = (id) ? this._findById(collection, id) : collection; 204 | if (!data) { 205 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "'" + collectionName + "' with id='" + id + "' not found"); 206 | } 207 | return new http_1.ResponseOptions({ 208 | body: {data: this._clone(data)}, 209 | headers: headers, 210 | status: http_status_codes_1.STATUS.OK 211 | }); 212 | }; 213 | InMemoryBackendService.prototype._getLocation = function(href) { 214 | var l = document.createElement('a'); 215 | l.href = href; 216 | return l; 217 | }; 218 | ; 219 | InMemoryBackendService.prototype._indexOf = function(collection, id) { 220 | return collection.findIndex(function(item) { 221 | return item.id === id; 222 | }); 223 | }; 224 | InMemoryBackendService.prototype._parseId = function(id) { 225 | if (!id) { 226 | return null; 227 | } 228 | var idNum = parseInt(id, 10); 229 | return isNaN(idNum) ? id : idNum; 230 | }; 231 | InMemoryBackendService.prototype._parseUrl = function(url) { 232 | try { 233 | var loc = this._getLocation(url); 234 | var drop = this._config.rootPath.length; 235 | var urlRoot = ''; 236 | if (loc.host !== this._config.host) { 237 | drop = 1; 238 | urlRoot = loc.protocol + '//' + loc.host + '/'; 239 | } 240 | var path = loc.pathname.substring(drop); 241 | var _a = path.split('/'), 242 | base = _a[0], 243 | collectionName = _a[1], 244 | id = _a[2]; 245 | var resourceUrl = urlRoot + base + '/' + collectionName + '/'; 246 | collectionName = collectionName.split('.')[0]; 247 | return { 248 | base: base, 249 | id: id, 250 | collectionName: collectionName, 251 | resourceUrl: resourceUrl 252 | }; 253 | } catch (err) { 254 | var msg = "unable to parse url '" + url + "'; original error: " + err.message; 255 | throw new Error(msg); 256 | } 257 | }; 258 | InMemoryBackendService.prototype._post = function(_a) { 259 | var collection = _a.collection, 260 | headers = _a.headers, 261 | id = _a.id, 262 | req = _a.req, 263 | resourceUrl = _a.resourceUrl; 264 | var item = JSON.parse(req.text()); 265 | if (!item.id) { 266 | item.id = id || this._genId(collection); 267 | } 268 | id = item.id; 269 | var existingIx = this._indexOf(collection, id); 270 | if (existingIx > -1) { 271 | collection[existingIx] = item; 272 | return new http_1.ResponseOptions({ 273 | headers: headers, 274 | status: http_status_codes_1.STATUS.NO_CONTENT 275 | }); 276 | } else { 277 | collection.push(item); 278 | headers.set('Location', resourceUrl + '/' + id); 279 | return new http_1.ResponseOptions({ 280 | headers: headers, 281 | body: {data: this._clone(item)}, 282 | status: http_status_codes_1.STATUS.CREATED 283 | }); 284 | } 285 | }; 286 | InMemoryBackendService.prototype._put = function(_a) { 287 | var id = _a.id, 288 | collection = _a.collection, 289 | collectionName = _a.collectionName, 290 | headers = _a.headers, 291 | req = _a.req; 292 | var item = JSON.parse(req.text()); 293 | if (!id) { 294 | return this._createErrorResponse(http_status_codes_1.STATUS.NOT_FOUND, "Missing '" + collectionName + "' id"); 295 | } 296 | if (id !== item.id) { 297 | return this._createErrorResponse(http_status_codes_1.STATUS.BAD_REQUEST, "\"" + collectionName + "\" id does not match item.id"); 298 | } 299 | var existingIx = this._indexOf(collection, id); 300 | if (existingIx > -1) { 301 | collection[existingIx] = item; 302 | return new http_1.ResponseOptions({ 303 | headers: headers, 304 | status: http_status_codes_1.STATUS.NO_CONTENT 305 | }); 306 | } else { 307 | collection.push(item); 308 | return new http_1.ResponseOptions({ 309 | body: {data: this._clone(item)}, 310 | headers: headers, 311 | status: http_status_codes_1.STATUS.CREATED 312 | }); 313 | } 314 | }; 315 | InMemoryBackendService.prototype._removeById = function(collection, id) { 316 | var ix = this._indexOf(collection, id); 317 | if (ix > -1) { 318 | collection.splice(ix, 1); 319 | return true; 320 | } 321 | return false; 322 | }; 323 | InMemoryBackendService.prototype._resetDb = function() { 324 | this._db = this._seedData.createDb(); 325 | }; 326 | InMemoryBackendService.prototype._setStatusText = function(options) { 327 | try { 328 | var statusCode = http_status_codes_1.STATUS_CODE_INFO[options.status]; 329 | options['statusText'] = statusCode ? statusCode.text : 'Unknown Status'; 330 | return options; 331 | } catch (err) { 332 | return new http_1.ResponseOptions({ 333 | status: http_status_codes_1.STATUS.INTERNAL_SERVER_ERROR, 334 | statusText: 'Invalid Server Operation' 335 | }); 336 | } 337 | }; 338 | InMemoryBackendService = __decorate([__param(0, core_1.Inject(SEED_DATA)), __param(1, core_1.Inject(InMemoryBackendConfig)), __param(1, core_1.Optional()), __metadata('design:paramtypes', [Object, Object])], InMemoryBackendService); 339 | return InMemoryBackendService; 340 | }()); 341 | exports_1("InMemoryBackendService", InMemoryBackendService); 342 | } 343 | }; 344 | }); 345 | 346 | System.register("a2-in-memory-web-api/http-status-codes", [], function(exports_1, context_1) { 347 | "use strict"; 348 | var __moduleName = context_1 && context_1.id; 349 | var STATUS, 350 | STATUS_CODE_INFO; 351 | return { 352 | setters: [], 353 | execute: function() { 354 | exports_1("STATUS", STATUS = { 355 | CONTINUE: 100, 356 | SWITCHING_PROTOCOLS: 101, 357 | OK: 200, 358 | CREATED: 201, 359 | ACCEPTED: 202, 360 | NON_AUTHORITATIVE_INFORMATION: 203, 361 | NO_CONTENT: 204, 362 | RESET_CONTENT: 205, 363 | PARTIAL_CONTENT: 206, 364 | MULTIPLE_CHOICES: 300, 365 | MOVED_PERMANTENTLY: 301, 366 | FOUND: 302, 367 | SEE_OTHER: 303, 368 | NOT_MODIFIED: 304, 369 | USE_PROXY: 305, 370 | TEMPORARY_REDIRECT: 307, 371 | BAD_REQUEST: 400, 372 | UNAUTHORIZED: 401, 373 | PAYMENT_REQUIRED: 402, 374 | FORBIDDEN: 403, 375 | NOT_FOUND: 404, 376 | METHOD_NOT_ALLOWED: 405, 377 | NOT_ACCEPTABLE: 406, 378 | PROXY_AUTHENTICATION_REQUIRED: 407, 379 | REQUEST_TIMEOUT: 408, 380 | CONFLICT: 409, 381 | GONE: 410, 382 | LENGTH_REQUIRED: 411, 383 | PRECONDITION_FAILED: 412, 384 | PAYLOAD_TO_LARGE: 413, 385 | URI_TOO_LONG: 414, 386 | UNSUPPORTED_MEDIA_TYPE: 415, 387 | RANGE_NOT_SATISFIABLE: 416, 388 | EXPECTATION_FAILED: 417, 389 | IM_A_TEAPOT: 418, 390 | UPGRADE_REQUIRED: 426, 391 | INTERNAL_SERVER_ERROR: 500, 392 | NOT_IMPLEMENTED: 501, 393 | BAD_GATEWAY: 502, 394 | SERVICE_UNAVAILABLE: 503, 395 | GATEWAY_TIMEOUT: 504, 396 | HTTP_VERSION_NOT_SUPPORTED: 505, 397 | PROCESSING: 102, 398 | MULTI_STATUS: 207, 399 | IM_USED: 226, 400 | PERMANENT_REDIRECT: 308, 401 | UNPROCESSABLE_ENTRY: 422, 402 | LOCKED: 423, 403 | FAILED_DEPENDENCY: 424, 404 | PRECONDITION_REQUIRED: 428, 405 | TOO_MANY_REQUESTS: 429, 406 | REQUEST_HEADER_FIELDS_TOO_LARGE: 431, 407 | UNAVAILABLE_FOR_LEGAL_REASONS: 451, 408 | VARIANT_ALSO_NEGOTIATES: 506, 409 | INSUFFICIENT_STORAGE: 507, 410 | NETWORK_AUTHENTICATION_REQUIRED: 511 411 | }); 412 | exports_1("STATUS_CODE_INFO", STATUS_CODE_INFO = { 413 | "100": { 414 | "code": 100, 415 | "text": "Continue", 416 | "description": "\"The initial part of a request has been received and has not yet been rejected by the server.\"", 417 | "spec_title": "RFC7231#6.2.1", 418 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.1" 419 | }, 420 | "101": { 421 | "code": 101, 422 | "text": "Switching Protocols", 423 | "description": "\"The server understands and is willing to comply with the client's request, via the Upgrade header field, for a change in the application protocol being used on this connection.\"", 424 | "spec_title": "RFC7231#6.2.2", 425 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.2.2" 426 | }, 427 | "200": { 428 | "code": 200, 429 | "text": "OK", 430 | "description": "\"The request has succeeded.\"", 431 | "spec_title": "RFC7231#6.3.1", 432 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.1" 433 | }, 434 | "201": { 435 | "code": 201, 436 | "text": "Created", 437 | "description": "\"The request has been fulfilled and has resulted in one or more new resources being created.\"", 438 | "spec_title": "RFC7231#6.3.2", 439 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 440 | }, 441 | "202": { 442 | "code": 202, 443 | "text": "Accepted", 444 | "description": "\"The request has been accepted for processing, but the processing has not been completed.\"", 445 | "spec_title": "RFC7231#6.3.3", 446 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.3" 447 | }, 448 | "203": { 449 | "code": 203, 450 | "text": "Non-Authoritative Information", 451 | "description": "\"The request was successful but the enclosed payload has been modified from that of the origin server's 200 (OK) response by a transforming proxy.\"", 452 | "spec_title": "RFC7231#6.3.4", 453 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.4" 454 | }, 455 | "204": { 456 | "code": 204, 457 | "text": "No Content", 458 | "description": "\"The server has successfully fulfilled the request and that there is no additional content to send in the response payload body.\"", 459 | "spec_title": "RFC7231#6.3.5", 460 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.5" 461 | }, 462 | "205": { 463 | "code": 205, 464 | "text": "Reset Content", 465 | "description": "\"The server has fulfilled the request and desires that the user agent reset the \"document view\", which caused the request to be sent, to its original state as received from the origin server.\"", 466 | "spec_title": "RFC7231#6.3.6", 467 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.6" 468 | }, 469 | "206": { 470 | "code": 206, 471 | "text": "Partial Content", 472 | "description": "\"The server is successfully fulfilling a range request for the target resource by transferring one or more parts of the selected representation that correspond to the satisfiable ranges found in the requests's Range header field.\"", 473 | "spec_title": "RFC7233#4.1", 474 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.1" 475 | }, 476 | "300": { 477 | "code": 300, 478 | "text": "Multiple Choices", 479 | "description": "\"The target resource has more than one representation, each with its own more specific identifier, and information about the alternatives is being provided so that the user (or user agent) can select a preferred representation by redirecting its request to one or more of those identifiers.\"", 480 | "spec_title": "RFC7231#6.4.1", 481 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.1" 482 | }, 483 | "301": { 484 | "code": 301, 485 | "text": "Moved Permanently", 486 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs.\"", 487 | "spec_title": "RFC7231#6.4.2", 488 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.2" 489 | }, 490 | "302": { 491 | "code": 302, 492 | "text": "Found", 493 | "description": "\"The target resource resides temporarily under a different URI.\"", 494 | "spec_title": "RFC7231#6.4.3", 495 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.3" 496 | }, 497 | "303": { 498 | "code": 303, 499 | "text": "See Other", 500 | "description": "\"The server is redirecting the user agent to a different resource, as indicated by a URI in the Location header field, that is intended to provide an indirect response to the original request.\"", 501 | "spec_title": "RFC7231#6.4.4", 502 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.4" 503 | }, 504 | "304": { 505 | "code": 304, 506 | "text": "Not Modified", 507 | "description": "\"A conditional GET request has been received and would have resulted in a 200 (OK) response if it were not for the fact that the condition has evaluated to false.\"", 508 | "spec_title": "RFC7232#4.1", 509 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.1" 510 | }, 511 | "305": { 512 | "code": 305, 513 | "text": "Use Proxy", 514 | "description": "*deprecated*", 515 | "spec_title": "RFC7231#6.4.5", 516 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.5" 517 | }, 518 | "307": { 519 | "code": 307, 520 | "text": "Temporary Redirect", 521 | "description": "\"The target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI.\"", 522 | "spec_title": "RFC7231#6.4.7", 523 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.4.7" 524 | }, 525 | "400": { 526 | "code": 400, 527 | "text": "Bad Request", 528 | "description": "\"The server cannot or will not process the request because the received syntax is invalid, nonsensical, or exceeds some limitation on what the server is willing to process.\"", 529 | "spec_title": "RFC7231#6.5.1", 530 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.1" 531 | }, 532 | "401": { 533 | "code": 401, 534 | "text": "Unauthorized", 535 | "description": "\"The request has not been applied because it lacks valid authentication credentials for the target resource.\"", 536 | "spec_title": "RFC7235#6.3.1", 537 | "spec_href": "http://tools.ietf.org/html/rfc7235#section-3.1" 538 | }, 539 | "402": { 540 | "code": 402, 541 | "text": "Payment Required", 542 | "description": "*reserved*", 543 | "spec_title": "RFC7231#6.5.2", 544 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.2" 545 | }, 546 | "403": { 547 | "code": 403, 548 | "text": "Forbidden", 549 | "description": "\"The server understood the request but refuses to authorize it.\"", 550 | "spec_title": "RFC7231#6.5.3", 551 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.3" 552 | }, 553 | "404": { 554 | "code": 404, 555 | "text": "Not Found", 556 | "description": "\"The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.\"", 557 | "spec_title": "RFC7231#6.5.4", 558 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.4" 559 | }, 560 | "405": { 561 | "code": 405, 562 | "text": "Method Not Allowed", 563 | "description": "\"The method specified in the request-line is known by the origin server but not supported by the target resource.\"", 564 | "spec_title": "RFC7231#6.5.5", 565 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.5" 566 | }, 567 | "406": { 568 | "code": 406, 569 | "text": "Not Acceptable", 570 | "description": "\"The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.\"", 571 | "spec_title": "RFC7231#6.5.6", 572 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.6" 573 | }, 574 | "407": { 575 | "code": 407, 576 | "text": "Proxy Authentication Required", 577 | "description": "\"The client needs to authenticate itself in order to use a proxy.\"", 578 | "spec_title": "RFC7231#6.3.2", 579 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.3.2" 580 | }, 581 | "408": { 582 | "code": 408, 583 | "text": "Request Timeout", 584 | "description": "\"The server did not receive a complete request message within the time that it was prepared to wait.\"", 585 | "spec_title": "RFC7231#6.5.7", 586 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.7" 587 | }, 588 | "409": { 589 | "code": 409, 590 | "text": "Conflict", 591 | "description": "\"The request could not be completed due to a conflict with the current state of the resource.\"", 592 | "spec_title": "RFC7231#6.5.8", 593 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.8" 594 | }, 595 | "410": { 596 | "code": 410, 597 | "text": "Gone", 598 | "description": "\"Access to the target resource is no longer available at the origin server and that this condition is likely to be permanent.\"", 599 | "spec_title": "RFC7231#6.5.9", 600 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.9" 601 | }, 602 | "411": { 603 | "code": 411, 604 | "text": "Length Required", 605 | "description": "\"The server refuses to accept the request without a defined Content-Length.\"", 606 | "spec_title": "RFC7231#6.5.10", 607 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.10" 608 | }, 609 | "412": { 610 | "code": 412, 611 | "text": "Precondition Failed", 612 | "description": "\"One or more preconditions given in the request header fields evaluated to false when tested on the server.\"", 613 | "spec_title": "RFC7232#4.2", 614 | "spec_href": "http://tools.ietf.org/html/rfc7232#section-4.2" 615 | }, 616 | "413": { 617 | "code": 413, 618 | "text": "Payload Too Large", 619 | "description": "\"The server is refusing to process a request because the request payload is larger than the server is willing or able to process.\"", 620 | "spec_title": "RFC7231#6.5.11", 621 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.11" 622 | }, 623 | "414": { 624 | "code": 414, 625 | "text": "URI Too Long", 626 | "description": "\"The server is refusing to service the request because the request-target is longer than the server is willing to interpret.\"", 627 | "spec_title": "RFC7231#6.5.12", 628 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.12" 629 | }, 630 | "415": { 631 | "code": 415, 632 | "text": "Unsupported Media Type", 633 | "description": "\"The origin server is refusing to service the request because the payload is in a format not supported by the target resource for this method.\"", 634 | "spec_title": "RFC7231#6.5.13", 635 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.13" 636 | }, 637 | "416": { 638 | "code": 416, 639 | "text": "Range Not Satisfiable", 640 | "description": "\"None of the ranges in the request's Range header field overlap the current extent of the selected resource or that the set of ranges requested has been rejected due to invalid ranges or an excessive request of small or overlapping ranges.\"", 641 | "spec_title": "RFC7233#4.4", 642 | "spec_href": "http://tools.ietf.org/html/rfc7233#section-4.4" 643 | }, 644 | "417": { 645 | "code": 417, 646 | "text": "Expectation Failed", 647 | "description": "\"The expectation given in the request's Expect header field could not be met by at least one of the inbound servers.\"", 648 | "spec_title": "RFC7231#6.5.14", 649 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.14" 650 | }, 651 | "418": { 652 | "code": 418, 653 | "text": "I'm a teapot", 654 | "description": "\"1988 April Fools Joke. Returned by tea pots requested to brew coffee.\"", 655 | "spec_title": "RFC 2324", 656 | "spec_href": "https://tools.ietf.org/html/rfc2324" 657 | }, 658 | "426": { 659 | "code": 426, 660 | "text": "Upgrade Required", 661 | "description": "\"The server refuses to perform the request using the current protocol but might be willing to do so after the client upgrades to a different protocol.\"", 662 | "spec_title": "RFC7231#6.5.15", 663 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.5.15" 664 | }, 665 | "500": { 666 | "code": 500, 667 | "text": "Internal Server Error", 668 | "description": "\"The server encountered an unexpected condition that prevented it from fulfilling the request.\"", 669 | "spec_title": "RFC7231#6.6.1", 670 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.1" 671 | }, 672 | "501": { 673 | "code": 501, 674 | "text": "Not Implemented", 675 | "description": "\"The server does not support the functionality required to fulfill the request.\"", 676 | "spec_title": "RFC7231#6.6.2", 677 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.2" 678 | }, 679 | "502": { 680 | "code": 502, 681 | "text": "Bad Gateway", 682 | "description": "\"The server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.\"", 683 | "spec_title": "RFC7231#6.6.3", 684 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.3" 685 | }, 686 | "503": { 687 | "code": 503, 688 | "text": "Service Unavailable", 689 | "description": "\"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance, which will likely be alleviated after some delay.\"", 690 | "spec_title": "RFC7231#6.6.4", 691 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.4" 692 | }, 693 | "504": { 694 | "code": 504, 695 | "text": "Gateway Time-out", 696 | "description": "\"The server, while acting as a gateway or proxy, did not receive a timely response from an upstream server it needed to access in order to complete the request.\"", 697 | "spec_title": "RFC7231#6.6.5", 698 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.5" 699 | }, 700 | "505": { 701 | "code": 505, 702 | "text": "HTTP Version Not Supported", 703 | "description": "\"The server does not support, or refuses to support, the protocol version that was used in the request message.\"", 704 | "spec_title": "RFC7231#6.6.6", 705 | "spec_href": "http://tools.ietf.org/html/rfc7231#section-6.6.6" 706 | }, 707 | "102": { 708 | "code": 102, 709 | "text": "Processing", 710 | "description": "\"An interim response to inform the client that the server has accepted the complete request, but has not yet completed it.\"", 711 | "spec_title": "RFC5218#10.1", 712 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.1" 713 | }, 714 | "207": { 715 | "code": 207, 716 | "text": "Multi-Status", 717 | "description": "\"Status for multiple independent operations.\"", 718 | "spec_title": "RFC5218#10.2", 719 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.2" 720 | }, 721 | "226": { 722 | "code": 226, 723 | "text": "IM Used", 724 | "description": "\"The server has fulfilled a GET request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance.\"", 725 | "spec_title": "RFC3229#10.4.1", 726 | "spec_href": "http://tools.ietf.org/html/rfc3229#section-10.4.1" 727 | }, 728 | "308": { 729 | "code": 308, 730 | "text": "Permanent Redirect", 731 | "description": "\"The target resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. [...] This status code is similar to 301 Moved Permanently (Section 7.3.2 of rfc7231), except that it does not allow rewriting the request method from POST to GET.\"", 732 | "spec_title": "RFC7238", 733 | "spec_href": "http://tools.ietf.org/html/rfc7238" 734 | }, 735 | "422": { 736 | "code": 422, 737 | "text": "Unprocessable Entity", 738 | "description": "\"The server understands the content type of the request entity (hence a 415(Unsupported Media Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad Request) status code is inappropriate) but was unable to process the contained instructions.\"", 739 | "spec_title": "RFC5218#10.3", 740 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.3" 741 | }, 742 | "423": { 743 | "code": 423, 744 | "text": "Locked", 745 | "description": "\"The source or destination resource of a method is locked.\"", 746 | "spec_title": "RFC5218#10.4", 747 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.4" 748 | }, 749 | "424": { 750 | "code": 424, 751 | "text": "Failed Dependency", 752 | "description": "\"The method could not be performed on the resource because the requested action depended on another action and that action failed.\"", 753 | "spec_title": "RFC5218#10.5", 754 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.5" 755 | }, 756 | "428": { 757 | "code": 428, 758 | "text": "Precondition Required", 759 | "description": "\"The origin server requires the request to be conditional.\"", 760 | "spec_title": "RFC6585#3", 761 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-3" 762 | }, 763 | "429": { 764 | "code": 429, 765 | "text": "Too Many Requests", 766 | "description": "\"The user has sent too many requests in a given amount of time (\"rate limiting\").\"", 767 | "spec_title": "RFC6585#4", 768 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-4" 769 | }, 770 | "431": { 771 | "code": 431, 772 | "text": "Request Header Fields Too Large", 773 | "description": "\"The server is unwilling to process the request because its header fields are too large.\"", 774 | "spec_title": "RFC6585#5", 775 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-5" 776 | }, 777 | "451": { 778 | "code": 451, 779 | "text": "Unavailable For Legal Reasons", 780 | "description": "\"The server is denying access to the resource in response to a legal demand.\"", 781 | "spec_title": "draft-ietf-httpbis-legally-restricted-status", 782 | "spec_href": "http://tools.ietf.org/html/draft-ietf-httpbis-legally-restricted-status" 783 | }, 784 | "506": { 785 | "code": 506, 786 | "text": "Variant Also Negotiates", 787 | "description": "\"The server has an internal configuration error: the chosen variant resource is configured to engage in transparent content negotiation itself, and is therefore not a proper end point in the negotiation process.\"", 788 | "spec_title": "RFC2295#8.1", 789 | "spec_href": "http://tools.ietf.org/html/rfc2295#section-8.1" 790 | }, 791 | "507": { 792 | "code": 507, 793 | "text": "Insufficient Storage", 794 | "description": "\The method could not be performed on the resource because the server is unable to store the representation needed to successfully complete the request.\"", 795 | "spec_title": "RFC5218#10.6", 796 | "spec_href": "http://tools.ietf.org/html/rfc2518#section-10.6" 797 | }, 798 | "511": { 799 | "code": 511, 800 | "text": "Network Authentication Required", 801 | "description": "\"The client needs to authenticate to gain network access.\"", 802 | "spec_title": "RFC6585#6", 803 | "spec_href": "http://tools.ietf.org/html/rfc6585#section-6" 804 | } 805 | }); 806 | } 807 | }; 808 | }); 809 | 810 | System.register("a2-in-memory-web-api/core", ["./in-memory-backend.service", "./http-status-codes"], function(exports_1, context_1) { 811 | "use strict"; 812 | var __moduleName = context_1 && context_1.id; 813 | function exportStar_1(m) { 814 | var exports = {}; 815 | for (var n in m) { 816 | if (n !== "default") 817 | exports[n] = m[n]; 818 | } 819 | exports_1(exports); 820 | } 821 | return { 822 | setters: [function(in_memory_backend_service_1_1) { 823 | exportStar_1(in_memory_backend_service_1_1); 824 | }, function(http_status_codes_1_1) { 825 | exportStar_1(http_status_codes_1_1); 826 | }], 827 | execute: function() {} 828 | }; 829 | }); 830 | --------------------------------------------------------------------------------