├── .editorconfig
├── .gitignore
├── .npmignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── backend.service.d.ts
├── backend.service.js
├── backend.service.js.map
├── backend.service.metadata.json
├── bundles
└── in-memory-web-api.umd.js
├── delay-response.d.ts
├── delay-response.js
├── delay-response.js.map
├── delay-response.metadata.json
├── gulpfile.js
├── http-client-backend.service.d.ts
├── http-client-backend.service.js
├── http-client-backend.service.js.map
├── http-client-backend.service.metadata.json
├── http-client-in-memory-web-api.module.d.ts
├── http-client-in-memory-web-api.module.js
├── http-client-in-memory-web-api.module.js.map
├── http-client-in-memory-web-api.module.metadata.json
├── http-client-in-memory-web-api.module.ngfactory.d.ts
├── http-client-in-memory-web-api.module.ngfactory.js
├── http-client-in-memory-web-api.module.ngfactory.js.map
├── http-status-codes.d.ts
├── http-status-codes.js
├── http-status-codes.js.map
├── http-status-codes.metadata.json
├── in-memory-web-api.module.d.ts
├── in-memory-web-api.module.js
├── in-memory-web-api.module.js.map
├── in-memory-web-api.module.metadata.json
├── in-memory-web-api.module.ngfactory.d.ts
├── in-memory-web-api.module.ngfactory.js
├── in-memory-web-api.module.ngfactory.js.map
├── index.d.ts
├── index.js
├── index.js.map
├── index.metadata.json
├── interfaces.d.ts
├── interfaces.js
├── interfaces.js.map
├── interfaces.metadata.json
├── karma-test-shim.js
├── karma.conf.js
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── app
│ ├── hero-in-mem-data-override.service.ts
│ ├── hero-in-mem-data.service.ts
│ ├── hero.service.spec.ts
│ ├── hero.service.ts
│ ├── hero.ts
│ └── http-client-hero.service.ts
├── in-mem
│ ├── backend.service.ngsummary.json
│ ├── backend.service.ts
│ ├── delay-response.ngsummary.json
│ ├── delay-response.ts
│ ├── http-client-backend.service.ngsummary.json
│ ├── http-client-backend.service.spec.ts
│ ├── http-client-backend.service.ts
│ ├── http-client-in-memory-web-api.module.ngsummary.json
│ ├── http-client-in-memory-web-api.module.ts
│ ├── http-status-codes.ngsummary.json
│ ├── http-status-codes.ts
│ ├── in-memory-web-api.module.ngsummary.json
│ ├── in-memory-web-api.module.ts
│ ├── index.ngsummary.json
│ ├── index.ts
│ ├── interfaces.ngsummary.json
│ └── interfaces.ts
├── systemjs-angular-loader.js
├── systemjs.config.js
└── testing
│ ├── index.ts
│ └── jasmine-ajax.spec.ts
├── tsconfig-ngc.json
├── tsconfig.json
└── tslint.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 |
12 | [*.md]
13 | max_line_length = 0
14 | trim_trailing_whitespace = false
15 |
16 | # Indentation override
17 | #[lib/**.js]
18 | #[{package.json,.travis.yml}]
19 | #[**/**.js]
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | aot
2 | in-memory-web-api
3 | node_modules
4 | typings
5 | npm-debug.log
6 | src/**/*.d.ts
7 | src/**/*.js
8 | src/**/*.js.map
9 | src/**/*.metadata.json
10 | yarn.lock
11 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .editorconfig
2 | .gitignore
3 | .npmignore
4 | .travis.yml
5 | aot
6 | gulpfile.js
7 | in-memory-web-api
8 | karma-test-shim.js
9 | karma.conf.js
10 | rollup.config.js
11 | src
12 | tsconfig.json
13 | tsconfig-ngc.json
14 | tslint.json
15 | yarn.lock
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 | language: node_js
4 | node_js:
5 | - "8"
6 | os:
7 | - linux
8 | env:
9 | global:
10 | - DBUS_SESSION_BUS_ADDRESS=/dev/null
11 | - DISPLAY=:99.0
12 | - CHROME_BIN=chromium-browser
13 | before_script:
14 | - sh -e /etc/init.d/xvfb start
15 | install:
16 | - npm install -g gulp
17 | - npm install
18 | script:
19 | - npm run lint
20 | - npm run tsc
21 | - gulp build
22 | - npm run test:once
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # "angular-in-memory-web-api" versions
2 | >This in-memory-web-api exists primarily to support the Angular documentation.
3 | It is not supposed to emulate every possible real world web API and is not intended for production use.
4 | >
5 | >Most importantly, it is ***always experimental***.
6 |
7 | We will make breaking changes and we won't feel bad about it
8 | because this is a development tool, not a production product.
9 | We do try to tell you about such changes in this `CHANGELOG.md`
10 | and we fix bugs as fast as we can.
11 |
12 |
13 | ## 0.10.0 (2020-05-13)
14 |
15 | * update to support Angular v10.
16 | * no functional changes.
17 |
18 |
19 | ## 0.9.0 (2019-06-20)
20 |
21 | * update to support Angular version 8.x and forward
22 | * no functional changes
23 |
24 |
25 | ## 0.8.0 (2018-12-06)
26 |
27 | * remove `@angular/http` support
28 | * no functional changes
29 |
30 | **BREAKING CHANGE**
31 | This version no longer supports any functionality for `@angular/http`. Please use
32 | `@angular/common/http` instead.
33 |
34 |
35 | ## 0.7.0 (2018-10-31)
36 |
37 | * update to support Angular v7.
38 | * no functional changes
39 |
40 |
41 | ## 0.6.1 (2018-05-04)
42 |
43 | * update to Angular and RxJS v6 releases
44 |
45 |
46 | ## 0.6.0 (2018-03-22)
47 |
48 | *Migrate to Angular v6 and RxJS v6 (rc and beta)*
49 |
50 | Note that this release is pinned to Angular "^6.0.0-rc.0" and RxJS "^6.0.0-beta.1".
51 | Will likely update again when they are official.
52 |
53 | **BREAKING CHANGE**
54 | This version depends on RxJS v6 and is not backward compatible with earlier RxJS versions.
55 |
56 |
57 | ## 0.5.4 (2018-03-09)
58 |
59 | Simulated HTTP error responses were not delaying the prescribed time when using RxJS `delay()`
60 | because it was short-circuited by the ErrorResponse.
61 | New `delayResponse` function does it right.
62 | Should not break you unless you incorrectly expected no delay for errors.
63 |
64 | Also, this library no longer calls RxJS `delay()` which may make testing with it easier
65 | (Angular TestBed does not handle RxJS `delay()` well because that operator uses `interval()`).
66 |
67 | Also fixes type error (issue #180).
68 |
69 |
70 | ## 0.5.3 (2018-01-06)
71 | Can make use of `HttpParams` which yields a `request.urlWithParams`.
72 | Added supporting `HeroService.searchHeroes(term: string)` and test.
73 |
74 |
75 | ## 0.5.2 (2017-12-10)
76 | No longer modify the request data coming from client. Fixes #164
77 |
78 |
79 | ## 0.5.1 (2017-10-21)
80 | Support Angular v5.
81 |
82 |
83 | ## 0.5.0 (2017-10-05)
84 | **BREAKING CHANGE**: HTTP response data no longer wrapped in object w/ `data` property by default.
85 |
86 | In this release, the `dataEncapsulation` configuration default changed from `false` to `true`. The HTTP response body holds the data values directly rather than an object that encapsulates those values, `{data: ...}`. This is a **breaking change that affects almost all existing apps!**
87 |
88 | Changing the default to `false` is a **breaking change**. Pre-existing apps that did not set this property explicitly will be broken because they expect encapsulation and are probably mapping
89 | the HTTP response results from the `data` property like this:
90 | ```
91 | .map(data => data.data as Hero[])
92 | ```
93 | **To migrate, simply remove that line everywhere.**
94 |
95 | If you would rather keep the web api's encapsulation, `{data: ...}`, set `dataEncapsulation` to `true` during configuration as in the following example:
96 | ```
97 | HttpClientInMemoryWebApiModule.forRoot(HeroInMemDataService, { dataEncapsulation: true })
98 | ```
99 |
100 | We made this change because
101 |
102 | 1. Almost everyone seems to hate the encapsulation
103 |
104 | 2. Encapsulation requires mapping to get the desired data out. With old `Http` that isn't _too_ bad because you needed to map to get data anyway (`res => res.json()`). But it is really ugly for `HttpClient` because you can't use the type HTTP method type parameter (e.g., `get`) and you have to map out of the data property (`.map(data => data.data as Hero[]`). That extra step requires explanations that distract from learning `HttpClient` itself.
105 | Now you just write `http.get()` and you’ve got data (please add error handling).
106 |
107 | 3. While you could have turned off encapsulation with configuration as of v.0.4, to do so took yet another step that you’d have to discover and explain. A big reason for the in-mem web api is to make it easy to introduce and demonstrate HTTP operations in Angular. The _out-of-box_ experience is more important than avoiding a breaking change.
108 |
109 | 4. The [security flaw](http://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk)
110 | that prompted encapsulation seems to have been mitigated by all (almost all?) the browsers that can run an Angular (v2+) app. We don’t think it’s needed anymore.
111 |
112 | 5. A most real world APIs today will not encapsulate; they’ll return the data in the body without extra ceremony.
113 |
114 |
115 | ## 0.4.6 (2017-09-13)
116 | - improves README
117 | - updates v0.4.0 entry in the CHANGELOG to describe essential additions to SystemJS configuration.
118 | - no important functional changes.
119 |
120 |
121 | ## 0.4.5 (2017-09-11)
122 | Feature - offer separate `HttpClientInMemoryWebApiModule` and `HttpInMemoryWebApiModule`.
123 |
124 | closes #140
125 |
126 |
127 | ## 0.4.4 (2017-09-11)
128 | closes #136
129 |
130 | A **breaking change** if you expected `genId` to generate ids for a collection
131 | with non-numeric `item.id`.
132 |
133 |
134 | ## 0.4.3 (2017-09-11)
135 | Refactoring for clarity and to correctly reflect intent.
136 | A **breaking change** only if your customizations depend directly and explicitly on `RequestInfo` or the `get`, `delete`, `post`, or `put` methods.
137 |
138 | - replace all `switchMap` with `concatMap` because, in all previous uses of `switchMap`,
139 | I really meant to wait for the source observable to complete _before_ beginning the inner observable whereas `switchMap` starts the inner observable right away.
140 |
141 | - restored `collection` to the `RequestInfo` interface and set it in `handleRequest_`
142 | - `get`, `delete`, `post`, and `put` methods get the `collection` from `requestInfo`; simplifies their signatures to one parameter.
143 |
144 |
145 | ## 0.4.2 (2017-09-08)
146 | - Postpones the in-memory database initialization (via `resetDb`) until the first HTTP request.
147 |
148 | - Your `createDb` method _can_ be asynchronous.
149 | You may return the database object (synchronous), an observable of it, or a promise of it. Issue #113.
150 |
151 | - fixed some rare race conditions.
152 |
153 |
154 | ## 0.4.1 (2017-09-08)
155 | **Support PassThru.**
156 |
157 | The passthru feature was broken by 0.4.0
158 | - add passthru to both `Http` and `HttpClient`
159 | - test passThru feature with jasmine-ajax mock-ajax plugin
160 | to intercept Angular's attempt to call browser's XHR
161 | - update devDependency packages
162 | - update karma.conf with jasmine-ajax plugin
163 |
164 |
165 | ## 0.4.0 (2017-09-07)
166 | **Theme: Support `HttpClient` and add tests**.
167 | See PR #130.
168 |
169 | The 0.4.0 release was a major overhaul of this library.
170 |
171 | You don't have to change your existing application _code_ if your app uses this library without customizations.
172 |
173 | But this release's **breaking changes** affect developers who used the customization features or loaded application files with SystemJS.
174 |
175 | **BREAKING CHANGES**: Massive refactoring.
176 | Many low-level and customization options have changed.
177 | Apps that stuck with defaults should be (mostly) OK.
178 |
179 | If you're loading application files with **SystemJS** (as you would in a plunker), see the [instructions below](#v-0-4-systemjs).
180 |
181 | * added support for `HttpClient` -> renaming of backend service classes
182 | * added tests
183 | * refactor existing code to support tests
184 | * correct bugs and clarify choices as result of test
185 | * add some configuration options
186 | - dataEncapsulation (issue #112, pr#123)
187 | - post409
188 | - put404b
189 | * `POST commands/resetDb` passes the request to your `resetDb` method
190 | so you can optionally reset the database dynamically
191 | to arbitrary initial states (issue #128)
192 | * when HTTP method interceptor returns null/undefined, continue with service's default processing (pr #120)
193 | * can substitute your own id generator, `geniD`
194 | * parseUrl -> parseRequestUrl
195 | * utility methods exposed in `RequestInfo.utils`
196 | * reorganize files into src/app and src/in-mem
197 | * adjust gulp tasks accordingly
198 |
199 | ---
200 |
201 |
202 | ### Plunkers and SystemJS
203 |
204 | If you’re loading application files with **SystemJS** (as you would in a plunker), you’ll have to configure it to load Angular’s `umd.js` for `HttpModule` and the `tslib` package.
205 |
206 | To see how, look in the `map` section of the
207 | [`src/systemjs.config.js` for this project](https://github.com/angular/in-memory-web-api/blob/master/src/systemjs.config.js) for the following two _additional_ lines :
208 |
209 | ```
210 | '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
211 | ...
212 | 'tslib': 'npm:tslib/tslib.js',
213 |
214 | ```
215 |
216 | You've already made these changes if you are using `HttpClient` today.
217 |
218 | If you’re sticking with the original Angular `Http` module, you _must make this change anyway!_ Your app will break as soon as you run `npm install` and it installs >=v0.4.0.
219 |
220 | If you're using webpack (as CLI devs do), you don't have to worry about this stuff because webpack bundles the dependencies for you.
221 |
222 | ---
223 |
224 |
225 | ## 0.3.2 (2017-05-02)
226 | * Bug fixes PRs #91, 95, 106
227 |
228 |
229 | ## 0.3.1 (2017-03-08)
230 | * Now runs in node so can use in "universal" demos.
231 | See PR #102.
232 |
233 |
234 | ## 0.3.0 (2017-02-27)
235 | * Support Angular version 4
236 |
237 |
238 | ## 0.2.4 (2017-01-02)
239 | * Remove reflect-matadata and zone.js as peerDependencies
240 |
241 |
242 | ## 0.2.3 (2016-12-28)
243 | * Unpin RxJs
244 |
245 |
246 | ## 0.2.2 (2016-12-20)
247 | * Update to Angular 2.4.0
248 |
249 |
250 | ## 0.2.1 (2016-12-14)
251 | * Fixed regression in handling commands, introduced in 0.2.0
252 | * Improved README
253 |
254 |
255 | ## 0.2.0 (2016-12-11)
256 |
257 | * BREAKING CHANGE: The observables returned by the `handleCollections` methods that process requests against the supplied in-mem-db collections are now "cold".
258 | That means that requests aren't processed until something subscribes to the observable ... just like real-world `Http` calls.
259 |
260 | Previously, these request were "hot" meaning that the operation was performed immediately
261 | (e.g., an in-memory collection was updated) and _then_ we returned an `Observable`.
262 | That was a mistake! Fixing that mistake _might_ break your app which is why bumped the _minor_ version number from 1 to 2.
263 |
264 | We hope _very few apps are broken by this change_. Most will have subscribed anyway.
265 | But any app that called an `http` method with fire-and-forget ... and didn't subscribe ...
266 | expecting the database to be updated (for example) will discover that the operation did ***not*** happen.
267 |
268 | * BREAKING CHANGE: `createErrorResponse` now requires the `Request` object as its first parameter
269 | so it can prepare a proper error message.
270 | For example, a 404 `errorResponse.toString()` now shows the request URL.
271 |
272 | * Commands remain "hot" — processed immediately — as they should be.
273 |
274 | * The `HTTP GET` interceptor in example `hero-data.service` shows how to create your own "cold" observable.
275 |
276 | * While you can still specify the `inMemDbService['responseInterceptor']` to morph the response options,
277 | the previously exported `responseInterceptor` function no longer exists as it served no useful purpose.
278 | Added the `ResponseInterceptor` _type_ to remind you of the signature to implement.
279 |
280 | * Allows objects with `id===0` (issue #56)
281 |
282 | * The default `parseUrl` method is more flexible, thanks in part to the new `config.apiBase` property.
283 | See the ReadMe to learn more.
284 |
285 | * Added `config.post204` and `config.put204` to control whether PUT and POST return the saved entity.
286 | It is `true` by default which means they do not return the entity (`status=204`) — the same behavior as before. (issue #74)
287 |
288 | * `response.url` is set to `request.url` when this service itself creates the response.
289 |
290 | * A few new methods (e.g., `emitResponse`) to assist in HTTP method interceptors.
291 |
292 |
293 |
294 |
295 | ## 0.1.17 (2016-12-07)
296 | * Update to Angular 2.2.0.
297 |
298 |
299 | ## 0.1.16 (2016-11-20)
300 | * Swap `"lib": [ "es2015", "dom" ]` in `tsconfig.json` for @types/core-js` in `package.json` issue #288
301 |
302 |
303 | ## 0.1.15 (2016-11-14)
304 | * Update to Angular 2.2.0.
305 |
306 |
307 | ## 0.1.14 (2016-10-29)
308 | * Add `responseInterceptor` for [issue #61](https://github.com/angular/in-memory-web-api/issues/61)
309 |
310 |
311 | ## 0.1.13 (2016-10-20)
312 | * Update README for 0.1.11 breaking change: npm publish as `esm` and a `umd` bundle
313 |
314 | Going to `umd` changes your `systemjs.config` and the way you import the library.
315 |
316 | In `systemjs.config.js` you should change the mapping to:
317 | ```
318 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
319 | ```
320 | then delete from `packages`:
321 | ```
322 | 'angular-in-memory-web-api': {
323 | main: './index.js',
324 | defaultExtension: 'js'
325 | }
326 | ```
327 | You must ES import the in-mem module (typically in `AppModule`) like this:
328 | ```
329 | import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
330 | ```
331 |
332 | ## 0.1.12 (2016-10-19)
333 | * exclude travis.yml and rollup.config.js from npm package
334 |
335 |
336 | ## 0.1.11 (2016-10-19)
337 | * BREAKING CHANGE: npm publish as `esm` and a `umd` bundle.
338 | Does not change the API but does change the way you register and import the
339 | in-mem module. Documented in later release, v.0.1.13
340 |
341 |
342 | ## 0.1.10 (2016-10-19)
343 | * Catch a `handleRequest` error and return as a failed server response.
344 |
345 |
346 | ## 0.1.9 (2016-10-18)
347 | * Restore delay option, issue #53.
348 |
349 |
350 | ## 0.1.7 (2016-10-12)
351 | * Angular 2.1.x support.
352 |
353 |
354 | ## 0.1.6 (2016-10-09)
355 | * Do not add delay to observable if delay value === 0 (issue #47)
356 | * Can override `parseUrl` method in your db service class (issue #46, #35)
357 | * README.md explains `parseUrl` override.
358 | * Exports functions helpful for custom HTTP Method Interceptors
359 | * `createErrorResponse`
360 | * `createObservableResponse`
361 | * `setStatusText`
362 | * Added `examples/hero-data.service.ts` to show overrides (issue #44)
363 |
364 |
365 | ## 0.1.5 (2016-10-03)
366 | * project.json license changed again to match angular.io package.json
367 |
368 |
369 | ## 0.1.4 (2016-10-03)
370 | * project.json license is "MIT"
371 |
372 |
373 | ## 0.1.3 (2016-09-29)
374 | * Fix typos
375 |
376 |
377 | ## 0.1.2 (2016-09-29)
378 | * AoT support from Tor PR #36
379 | * Update npm packages
380 | * `parseId` fix from PR #33
381 |
382 |
383 | ## 0.1.1 (2016-09-26)
384 | * Exclude src folder and its TS files from npm package
385 |
386 |
387 | ## 0.1.0 (2016-09-25)
388 | * Renamed package to "angular-in-memory-web-api"
389 | * Added "passThruUnknownUrl" options
390 | * Simplified `forRoot` and made it acceptable to AoT
391 | * Support case sensitive search (PR #16)
392 |
393 | # "angular2-in-memory-web-api" versions
394 | The last npm package named "angular2-in-memory-web-api" was v.0.0.21
395 |
396 |
397 | ## 0.0.21 (2016-09-25)
398 | * Add source maps (PR #14)
399 |
400 |
401 | ## 0.0.20 (2016-09-15)
402 | * Angular 2.0.0
403 | * Typescript 2.0.2
404 |
405 |
406 | ## 0.0.19 (2016-09-13)
407 | * RC7
408 |
409 |
410 | ## 0.0.18 (2016-08-31)
411 | * RC6 (doesn't work with older versions)
412 |
413 |
414 | ## 0.0.17 (2016-08-19)
415 | * fix `forRoot` type constraint
416 | * clarify `forRoot` param
417 |
418 |
419 | ## 0.0.16 (2016-08-19)
420 | * No longer exports `HttpModule`
421 | * Can specify configuration options in 2nd param of `forRoot`
422 | * jsDocs for `forRoot`
423 |
424 |
425 | ## 0.0.15 (2016-08-09)
426 | * RC5
427 | * Support for NgModules
428 |
429 |
430 | ## 0.0.14 (2016-06-30)
431 | * RC4
432 |
433 |
434 | ## 0.0.13 (2016-06-21)
435 | * RC3
436 |
437 |
438 | ## 0.0.12 (2016-06-15)
439 | * RC2
440 |
441 |
442 | ## 0.0.11 (2016-05-27)
443 | * add RegExp query support
444 | * find-by-id is sensitive to string ids that look like numbers
445 |
446 |
447 | ## 0.0.10 (2016-05-21)
448 | * added "main:index.js" to package.json
449 | * updated to typings v.1.0.4 (a breaking release)
450 | * dependencies -> peerDependencies|devDependencies
451 | * no es6-shim dependency.
452 | * use core-js as devDependency.
453 |
454 |
455 | ## 0.0.9 (2016-05-19)
456 | * renamed the barrel core.js -> index.js
457 |
458 |
459 | ## 0.0.8 (2016-05-19)
460 | * systemjs -> commonjs
461 | * replace es6-shim typings w/ core-js typings
462 |
463 |
464 | ## 0.0.7 (2016-05-03)
465 | * RC1
466 | * update to 2.0.0-rc.1
467 |
468 |
469 | ## 0.0.6 (2016-05-03)
470 | * RC0
471 | * update to 2.0.0-rc.0
472 |
473 |
474 | ## 0.0.5 (2016-05-01)
475 | * PROVISIONAL - refers to @angular packages
476 | * update to 0.0.0-5
477 |
478 |
479 | ## 0.0.4 (2016-04-30)
480 | * PROVISIONAL - refers to @angular packages
481 | * update to 0.0.0-3
482 | * rxjs: "5.0.0-beta.6"
483 |
484 |
485 | ## 0.0.3 (2016-04-29)
486 | * PROVISIONAL - refers to @angular packages
487 | * update to 0.0.0-2
488 |
489 |
490 | ## 0.0.2 (2016-04-27)
491 | * PROVISIONAL - refers to @angular packages
492 |
493 |
494 | ## 0.0.1 (2016-04-27)
495 | * DO NOT USE. Not adapted to new package system.
496 | * Initial cut for Angular 2 repackaged
497 | * target forthcoming Angular 2 RC
498 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2016 Google, Inc.
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular in-memory-web-api
2 | [![Build Status][travis-badge]][travis-badge-url]
3 |
4 | An in-memory web api for Angular demos and tests
5 | that emulates CRUD operations over a RESTy API.
6 |
7 | It intercepts Angular `Http` and `HttpClient` requests that would otherwise go to the remote server and redirects them to an in-memory data store that you control.
8 |
9 | See [Austin McDaniel's article](https://medium.com/@amcdnl/mocking-with-angular-more-than-just-unit-testing-cbb7908c9fcc)
10 | for a quick introduction.
11 |
12 | ### _It used to work and now it doesn't :-(_
13 |
14 | Perhaps you installed a new version of this library? Check the
15 | [CHANGELOG.md](https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md)
16 | for breaking changes that may have affected your app.
17 |
18 | If that doesn't explain it, create an
19 | [issue on github](https://github.com/angular/in-memory-web-api/issues),
20 | preferably with a small repro.
21 |
22 | ## Use cases
23 |
24 | * Demo apps that need to simulate CRUD data persistence operations without a real server.
25 | You won't have to build and start a test server.
26 |
27 | * Whip up prototypes and proofs of concept.
28 |
29 | * Share examples with the community in a web coding environment such as Plunker or CodePen.
30 | Create Angular issues and StackOverflow answers supported by live code.
31 |
32 | * Simulate operations against data collections that aren't yet implemented on your dev/test server.
33 | You can pass requests thru to the dev/test server for collections that are supported.
34 |
35 | * Write unit test apps that read and write data.
36 | Avoid the hassle of intercepting multiple http calls and manufacturing sequences of responses.
37 | The in-memory data store resets for each test so there is no cross-test data pollution.
38 |
39 | * End-to-end tests. If you can toggle the app into test mode
40 | using the in-memory web api, you won't disturb the real database.
41 | This can be especially useful for CI (continuous integration) builds.
42 |
43 |
44 | >**LIMITATIONS**
45 | >
46 | >The _in-memory-web-api_ exists primarily to support the
47 | [Angular documentation](https://angular.io/docs/ts/latest/ "Angular documentation web site").
48 | It is not supposed to emulate every possible real world web API and is not intended for production use.
49 | >
50 | >Most importantly, it is ***always experimental***.
51 | We will make breaking changes and we won't feel bad about it
52 | because this is a development tool, not a production product.
53 | We do try to tell you about such changes in the `CHANGELOG.md`
54 | and we fix bugs as fast as we can.
55 |
56 | ## HTTP request handling
57 | This in-memory web api service processes an HTTP request and
58 | returns an `Observable` of HTTP `Response` object
59 | in the manner of a RESTy web api.
60 | It natively handles URI patterns in the form `:base/:collectionName/:id?`
61 |
62 | Examples:
63 | ```ts
64 | // for requests to an `api` base URL that gets heroes from a 'heroes' collection
65 | GET api/heroes // all heroes
66 | GET api/heroes/42 // the hero with id=42
67 | GET api/heroes?name=^j // 'j' is a regex; returns heroes whose name starting with 'j' or 'J'
68 | GET api/heroes.json/42 // ignores the ".json"
69 | ```
70 |
71 | The in-memory web api service processes these requests against a "database" - a set of named collections - that you define during setup.
72 |
73 | ## Basic setup
74 |
75 |
76 |
77 | Create an `InMemoryDataService` class that implements `InMemoryDbService`.
78 |
79 | At minimum it must implement `createDb` which
80 | creates a "database" hash whose keys are collection names
81 | and whose values are arrays of collection objects to return or update.
82 | For example:
83 | ```ts
84 | import { InMemoryDbService } from 'angular-in-memory-web-api';
85 |
86 | export class InMemHeroService implements InMemoryDbService {
87 | createDb() {
88 | let heroes = [
89 | { id: 1, name: 'Windstorm' },
90 | { id: 2, name: 'Bombasto' },
91 | { id: 3, name: 'Magneta' },
92 | { id: 4, name: 'Tornado' }
93 | ];
94 | return {heroes};
95 | }
96 | }
97 | ```
98 |
99 | **Notes**
100 |
101 | * The in-memory web api library _currently_ assumes that every collection has a primary key called `id`.
102 |
103 | * The `createDb` method can be synchronous or asynchronous.
104 | It would have to be asynchronous if you initialized your in-memory database service from a JSON file.
105 | Return the database _object_, an _observable_ of that object, or a _promise_ of that object. The tests include an example of all three.
106 |
107 | * The in-memory web api calls your `InMemoryDbService` data service class's `createDb` method on two occasions.
108 |
109 | 1. when it handles the _first_ HTTP request
110 | 1. when it receives a `resetdb` [command](#commands).
111 |
112 | In the command case, the service passes in a `RequestInfo` object,
113 | enabling the `createDb` logic to adjust its behavior per the client request. See the tests for examples.
114 |
115 | ### Import the in-memory web api module
116 |
117 | Register your data store service implementation with the `HttpClientInMemoryWebApiModule`
118 | in your root `AppModule.imports`
119 | calling the `forRoot` static method with this service class and an optional configuration object:
120 | ```ts
121 | import { HttpClientModule } from '@angular/common/http';
122 | import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
123 |
124 | import { InMemHeroService } from '../app/hero.service';
125 |
126 | @NgModule({
127 | imports: [
128 | HttpClientModule,
129 | HttpClientInMemoryWebApiModule.forRoot(InMemHeroService),
130 | ...
131 | ],
132 | ...
133 | })
134 | export class AppModule { ... }
135 | ```
136 |
137 | **_Notes_**
138 |
139 | * Always import the `HttpClientInMemoryWebApiModule` _after_ the `HttpClientModule`
140 | to ensure that the in-memory backend provider supersedes the Angular version.
141 |
142 | * You can setup the in-memory web api within a lazy loaded feature module by calling the `.forFeature` method as you would `.forRoot`.
143 |
144 | * In production, you want HTTP requests to go to the real server and probably have no need for the _in-memory_ provider.
145 | CLI-based apps can exclude the provider in production builds like this:
146 | ```ts
147 | imports: [
148 | HttpClientModule,
149 | environment.production ?
150 | [] : HttpClientInMemoryWebApiModule.forRoot(InMemHeroService)
151 | ...
152 | ]
153 | ```
154 |
155 | # Examples
156 | The tests (`src/app/*.spec.ts` files) in the
157 | [github repository](https://github.com/angular/in-memory-web-api/tree/master/src/app)
158 | are a good place to learn how to setup and use this in-memory web api library.
159 |
160 | See also the example source code in the official Angular.io documentation such as the
161 | [HttpClient](https://angular.io/guide/http) guide and the
162 | [Tour of Heroes](https://angular.io/tutorial/toh-pt6).
163 |
164 | # Advanced Features
165 | Some features are not readily apparent in the basic usage described above.
166 |
167 | ## Configuration arguments
168 |
169 | The `InMemoryBackendConfigArgs` defines a set of options. Add them as the second `forRoot` argument:
170 | ```ts
171 | InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 500 }),
172 | ```
173 |
174 | **Read the `InMemoryBackendConfigArgs` interface to learn about these options**.
175 |
176 |
177 | ## Request evaluation order
178 | This service can evaluate requests in multiple ways depending upon the configuration.
179 | Here's how it reasons:
180 | 1. If it looks like a [command](#commands), process as a command
181 | 2. If the [HTTP method is overridden](#method-override), try the override.
182 | 3. If the resource name (after the api base path) matches one of the configured collections, process that
183 | 4. If not but the `Config.passThruUnknownUrl` flag is `true`, try to [pass the request along to a real _XHR_](#passthru).
184 | 5. Return a 404.
185 |
186 | See the `handleRequest` method implementation for details.
187 |
188 | ## Default delayed response
189 |
190 | By default this service adds a 500ms delay
191 | to all data requests to simulate round-trip latency.
192 |
193 | >[Command requests](#commands) have zero added delay as they concern
194 | in-memory service configuration and do not emulate real data requests.
195 |
196 | You can change or eliminate the latency by setting a different `delay` value:
197 | ```ts
198 | InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 0 }), // no delay
199 | InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 1500 }), // 1.5 second delay
200 | ```
201 |
202 | ## Simple query strings
203 | Pass custom filters as a regex pattern via query string.
204 | The query string defines which property and value to match.
205 |
206 | Format: `/app/heroes/?propertyName=regexPattern`
207 |
208 | The following example matches all names start with the letter 'j' or 'J' in the heroes collection.
209 |
210 | `/app/heroes/?name=^j`
211 |
212 | >Search pattern matches are case insensitive by default.
213 | Set `config.caseSensitiveSearch = true` if needed.
214 |
215 |
216 | ## Pass thru to a live server
217 |
218 | If an existing, running remote server should handle requests for collections
219 | that are not in the in-memory database, set `Config.passThruUnknownUrl: true`.
220 | Then this service will forward unrecognized requests to the remote server
221 | via the Angular default `XHR` backend (it depends on whether your using `Http` or `HttpClient`).
222 |
223 |
224 | ## Commands
225 |
226 | The client may issue a command request to get configuration state
227 | from the in-memory web api service, reconfigure it,
228 | or reset the in-memory database.
229 |
230 | When the last segment of the _api base path_ is "commands", the `collectionName` is treated as the _command_.
231 |
232 | Example URLs:
233 | ```sh
234 | commands/resetdb // Reset the "database" to its original state
235 | commands/config // Get or update this service's config object
236 | ```
237 |
238 | Usage:
239 | ```sh
240 | http.post('commands/resetdb', undefined);
241 | http.get('commands/config');
242 | http.post('commands/config', '{"delay":1000}');
243 | ```
244 |
245 | Command requests do not simulate real remote data access.
246 | They ignore the latency delay and respond as quickly as possible.
247 |
248 | The `resetDb` command
249 | calls your `InMemoryDbService` data service's [`createDb` method](#createDb) with the `RequestInfo` object,
250 | enabling the `createDb` logic to adjust its behavior per the client request.
251 |
252 | In the following example, the client includes a reset option in the command request body:
253 | ```ts
254 | http
255 | // Reset the database collections with the `clear` option
256 | .post('commands/resetDb', { clear: true }))
257 |
258 | // when command finishes, get heroes
259 | .concatMap(
260 | ()=> http.get('api/heroes')
261 | .map(data => data.data as Hero[])
262 | )
263 |
264 | // execute the request sequence and
265 | // do something with the heroes
266 | .subscribe(...)
267 | ```
268 |
269 | See the tests for other examples.
270 |
271 | ## _parseRequestUrl_
272 |
273 | The `parseRequestUrl` parses the request URL into a `ParsedRequestUrl` object.
274 | `ParsedRequestUrl` is a public interface whose properties guide the in-memory web api
275 | as it processes the request.
276 |
277 | ### Default _parseRequestUrl_
278 |
279 | Default parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.
280 | Read the source code for the complete story.
281 |
282 | Configuring the `apiBase` yields the most interesting changes to `parseRequestUrl` behavior:
283 |
284 | * For `apiBase=undefined` and `url='http://localhost/api/customers/42'`
285 | ```ts
286 | {apiBase: 'api/', collectionName: 'customers', id: '42', ...}
287 | ```
288 |
289 | * For `apiBase='some/api/root/'` and `url='http://localhost/some/api/root/customers'`
290 | ```ts
291 | { apiBase: 'some/api/root/', collectionName: 'customers', id: undefined, ... }
292 | ```
293 |
294 | * For `apiBase='/'` and `url='http://localhost/customers'`
295 | ```ts
296 | { apiBase: '/', collectionName: 'customers', id: undefined, ... }
297 | ```
298 |
299 | **The actual api base segment values are ignored**. Only the number of segments matters.
300 | The following api base strings are considered identical: 'a/b' ~ 'some/api/' ~ `two/segments'
301 |
302 | This means that URLs that work with the in-memory web api may be rejected by the real server.
303 |
304 | ### Custom _parseRequestUrl_
305 |
306 | You can override the default parser by implementing a `parseRequestUrl` method in your `InMemoryDbService`.
307 |
308 | The service calls your method with two arguments.
309 | 1. `url` - the request URL string
310 | 1. `requestInfoUtils` - utility methods in a `RequestInfoUtilities` object, including the default parser.
311 | Note that some values have not yet been set as they depend on the outcome of parsing.
312 |
313 | Your method must either return a `ParsedRequestUrl` object or `null`|`undefined`,
314 | in which case the service uses the default parser.
315 | In this way you can intercept and parse some URLs and leave the others to the default parser.
316 |
317 | ## Custom _genId_
318 |
319 | Collection items are presumed to have a primary key property called `id`.
320 |
321 | You can specify the `id` while adding a new item.
322 | The service will blindly use that `id`; it does not check for uniqueness.
323 |
324 | If you do not specify the `id`, the service generates one via the `genId` method.
325 |
326 | You can override the default id generator with a method called `genId` in your `InMemoryDbService`.
327 | Your method receives the new item's collection and collection name.
328 | It should return the generated id.
329 | If your generator returns `null`|`undefined`, the service uses the default generator.
330 |
331 | ## _responseInterceptor_
332 |
333 | You can change the response returned by the service's default HTTP methods.
334 | A typical reason to intercept is to add a header that your application is expecting.
335 |
336 | To intercept responses, add a `responseInterceptor` method to your `InMemoryDbService` class.
337 | The service calls your interceptor like this:
338 | ```ts
339 | responseOptions = this.responseInterceptor(responseOptions, requestInfo);
340 | ```
341 |
342 |
343 | ## HTTP method interceptors
344 |
345 | You may have HTTP requests that the in-memory web api can't handle properly.
346 |
347 | You can override any HTTP method by implementing a method
348 | of that name in your `InMemoryDbService`.
349 |
350 | Your method's name must be the same as the HTTP method name but **all lowercase**.
351 | The in-memory web api calls it with a `RequestInfo` object that contains request data and utility methods.
352 |
353 | For example, if you implemented a `get` method, the web api would be called like this:
354 | `yourInMemDbService["get"](requestInfo)`.
355 |
356 | Your custom HTTP method must return either:
357 |
358 | * `Observable` - you handled the request and the response is available from this
359 | observable. It _should be "cold"_.
360 |
361 | * `null`/`undefined` - you decided not to intervene,
362 | perhaps because you wish to intercept only certain paths for the given HTTP method.
363 | The service continues with its default processing of the HTTP request.
364 |
365 | The `RequestInfo` is an interface defined in `src/in-mem/interfaces.ts`.
366 | Its members include:
367 | ```ts
368 | req: Request; // the request object from the client
369 | collectionName: string; // calculated from the request url
370 | collection: any[]; // the corresponding collection (if found)
371 | id: any; // the item `id` (if specified)
372 | url: string; // the url in the request
373 | utils: RequestInfoUtilities; // helper functions
374 | ```
375 | The functions in `utils` can help you analyze the request
376 | and compose a response.
377 |
378 | ## In-memory Web Api Examples
379 |
380 | The [github repository](https://github.com/angular/in-memory-web-api/tree/master/src/app)
381 | demonstrates library usage with tested examples.
382 |
383 | The `HeroInMemDataService` class (in `src/app/hero-in-mem-data.service.ts`) is a Hero-oriented `InMemoryDbService`
384 | such as you might see in an HTTP sample in the Angular documentation.
385 |
386 | The `HeroInMemDataOverrideService` class (in `src/app/hero-in-mem-data-override.service.ts`)
387 | demonstrates a few ways to override methods of the base `HeroInMemDataService`.
388 |
389 | The tests ([see below](#testing)) exercise these examples.
390 |
391 | # Build Instructions
392 |
393 | Follow these steps for updating the library.
394 |
395 | - `gulp bump` - up the package version number.
396 |
397 | - update `CHANGELOG.md` to record the change. Call out _breaking changes_.
398 |
399 | - update `README.md` if usage or interfaces change.
400 |
401 | - consider updating the dependency versions in `package.json`.
402 |
403 | - `npm install` the new package(s) if you did.
404 |
405 | - `npm list --depth=0` to make sure they really did install!
406 |
407 | - `gulp clean` to delete all generated files.
408 |
409 | - `npm test` to dev-build and run tests (see ["Testing"](#testing) below).
410 |
411 | - `gulp build` to build for distribution.
412 |
413 | - git add, commit, and push.
414 |
415 | - `npm publish`
416 |
417 | - Confirm that angular.io docs samples still work
418 |
419 | - Add two tags to the release commit in github
420 | - the version number
421 | - 'latest'
422 |
423 | [travis-badge]: https://travis-ci.org/angular/in-memory-web-api.svg?branch=master
424 | [travis-badge-url]: https://travis-ci.org/angular/in-memory-web-api
425 |
426 | ## Testing
427 |
428 | The "app" for this repo is not a real app.
429 | It's an Angular data service (`HeroService`) and a bunch of tests.
430 |
431 | >Note that the `tsconfig.json` produces a `commonjs` module.
432 | That's what _Angular specs require_.
433 | But when building for an app, it should be a `es2015` module,
434 | as is the `tsconfig-ngc.json` for AOT-ready version of this library.
435 |
436 | These tests are a work-in-progress, as tests often are.
437 |
438 | The `src/` folder is divided into
439 | - `app/` - the test "app" and its tests
440 | - `in-mem/` - the source code for the in-memory web api library
441 |
442 | >A real app would reference the in-memory web api node module;
443 | these tests reference the library source files.
444 |
445 | The `karma-test-shim.js` adds the `in-mem` folder to the list of folders that SystemJS should resolve.
446 |
447 | ## Rollup
448 |
449 | The gulp "umd" task runs rollup for tree-shaking.
450 |
451 | I don't remember if it ever worked without a lot of warnings.
452 | The `v0.4.x` release updated to `rollup@0.49` which required updates to the `rollup.config.js`.
453 |
454 | Still weirdly runs `cjs` rollup config first that I can’t find (which produces numerous warnings) before doing the right thing and running the `umd` config.
455 |
456 | Also does not work if you follow instructions and use the `output` property of `rollup.config.js`; does work when configure it “wrong” and put the options in the root.
457 |
458 | Ignoring these issues for now.
459 |
460 |
--------------------------------------------------------------------------------
/backend.service.d.ts:
--------------------------------------------------------------------------------
1 | import { Observable, BehaviorSubject } from 'rxjs';
2 | import { HeadersCore, RequestInfoUtilities, InMemoryDbService, InMemoryBackendConfigArgs, ParsedRequestUrl, PassThruBackend, RequestCore, RequestInfo, ResponseOptions, UriInfo } from './interfaces';
3 | /**
4 | * Base class for in-memory web api back-ends
5 | * Simulate the behavior of a RESTy web api
6 | * backed by the simple in-memory data store provided by the injected `InMemoryDbService` service.
7 | * Conforms mostly to behavior described here:
8 | * http://www.restapitutorial.com/lessons/httpmethods.html
9 | */
10 | export declare abstract class BackendService {
11 | protected inMemDbService: InMemoryDbService;
12 | protected config: InMemoryBackendConfigArgs;
13 | protected db: Object;
14 | protected dbReadySubject: BehaviorSubject;
15 | private passThruBackend;
16 | protected requestInfoUtils: RequestInfoUtilities;
17 | constructor(inMemDbService: InMemoryDbService, config?: InMemoryBackendConfigArgs);
18 | protected readonly dbReady: Observable;
19 | /**
20 | * Process Request and return an Observable of Http Response object
21 | * in the manner of a RESTy web api.
22 | *
23 | * Expect URI pattern in the form :base/:collectionName/:id?
24 | * Examples:
25 | * // for store with a 'customers' collection
26 | * GET api/customers // all customers
27 | * GET api/customers/42 // the character with id=42
28 | * GET api/customers?name=^j // 'j' is a regex; returns customers whose name starts with 'j' or 'J'
29 | * GET api/customers.json/42 // ignores the ".json"
30 | *
31 | * Also accepts direct commands to the service in which the last segment of the apiBase is the word "commands"
32 | * Examples:
33 | * POST commands/resetDb,
34 | * GET/POST commands/config - get or (re)set the config
35 | *
36 | * HTTP overrides:
37 | * If the injected inMemDbService defines an HTTP method (lowercase)
38 | * The request is forwarded to that method as in
39 | * `inMemDbService.get(requestInfo)`
40 | * which must return either an Observable of the response type
41 | * for this http library or null|undefined (which means "keep processing").
42 | */
43 | protected handleRequest(req: RequestCore): Observable;
44 | protected handleRequest_(req: RequestCore): Observable;
45 | /**
46 | * Add configured delay to response observable unless delay === 0
47 | */
48 | protected addDelay(response: Observable): Observable;
49 | /**
50 | * Apply query/search parameters as a filter over the collection
51 | * This impl only supports RegExp queries on string properties of the collection
52 | * ANDs the conditions together
53 | */
54 | protected applyQuery(collection: any[], query: Map): any[];
55 | /**
56 | * Get a method from the `InMemoryDbService` (if it exists), bound to that service
57 | */
58 | protected bind(methodName: string): T;
59 | protected bodify(data: any): any;
60 | protected clone(data: any): any;
61 | protected collectionHandler(reqInfo: RequestInfo): ResponseOptions;
62 | /**
63 | * Commands reconfigure the in-memory web api service or extract information from it.
64 | * Commands ignore the latency delay and respond ASAP.
65 | *
66 | * When the last segment of the `apiBase` path is "commands",
67 | * the `collectionName` is the command.
68 | *
69 | * Example URLs:
70 | * commands/resetdb (POST) // Reset the "database" to its original state
71 | * commands/config (GET) // Return this service's config object
72 | * commands/config (POST) // Update the config (e.g. the delay)
73 | *
74 | * Usage:
75 | * http.post('commands/resetdb', undefined);
76 | * http.get('commands/config');
77 | * http.post('commands/config', '{"delay":1000}');
78 | */
79 | protected commands(reqInfo: RequestInfo): Observable;
80 | protected createErrorResponseOptions(url: string, status: number, message: string): ResponseOptions;
81 | /**
82 | * Create standard HTTP headers object from hash map of header strings
83 | * @param headers
84 | */
85 | protected abstract createHeaders(headers: {
86 | [index: string]: string;
87 | }): HeadersCore;
88 | /**
89 | * create the function that passes unhandled requests through to the "real" backend.
90 | */
91 | protected abstract createPassThruBackend(): PassThruBackend;
92 | /**
93 | * return a search map from a location query/search string
94 | */
95 | protected abstract createQueryMap(search: string): Map;
96 | /**
97 | * Create a cold response Observable from a factory for ResponseOptions
98 | * @param resOptionsFactory - creates ResponseOptions when observable is subscribed
99 | * @param withDelay - if true (default), add simulated latency delay from configuration
100 | */
101 | protected createResponse$(resOptionsFactory: () => ResponseOptions, withDelay?: boolean): Observable;
102 | /**
103 | * Create a Response observable from ResponseOptions observable.
104 | */
105 | protected abstract createResponse$fromResponseOptions$(resOptions$: Observable): Observable;
106 | /**
107 | * Create a cold Observable of ResponseOptions.
108 | * @param resOptionsFactory - creates ResponseOptions when observable is subscribed
109 | */
110 | protected createResponseOptions$(resOptionsFactory: () => ResponseOptions): Observable;
111 | protected delete({ collection, collectionName, headers, id, url }: RequestInfo): ResponseOptions;
112 | /**
113 | * Find first instance of item in collection by `item.id`
114 | * @param collection
115 | * @param id
116 | */
117 | protected findById(collection: T[], id: any): T;
120 | /**
121 | * Generate the next available id for item in this collection
122 | * Use method from `inMemDbService` if it exists and returns a value,
123 | * else delegates to `genIdDefault`.
124 | * @param collection - collection of items with `id` key property
125 | */
126 | protected genId(collection: T[], collectionName: string): any;
129 | /**
130 | * Default generator of the next available id for item in this collection
131 | * This default implementation works only for numeric ids.
132 | * @param collection - collection of items with `id` key property
133 | * @param collectionName - name of the collection
134 | */
135 | protected genIdDefault(collection: T[], collectionName: string): any;
138 | protected get({ collection, collectionName, headers, id, query, url }: RequestInfo): ResponseOptions;
139 | /** Get JSON body from the request object */
140 | protected abstract getJsonBody(req: any): any;
141 | /**
142 | * Get location info from a url, even on server where `document` is not defined
143 | */
144 | protected getLocation(url: string): UriInfo;
145 | /**
146 | * get or create the function that passes unhandled requests
147 | * through to the "real" backend.
148 | */
149 | protected getPassThruBackend(): PassThruBackend;
150 | /**
151 | * Get utility methods from this service instance.
152 | * Useful within an HTTP method override
153 | */
154 | protected getRequestInfoUtils(): RequestInfoUtilities;
155 | /**
156 | * return canonical HTTP method name (lowercase) from the request object
157 | * e.g. (req.method || 'get').toLowerCase();
158 | * @param req - request object from the http call
159 | *
160 | */
161 | protected abstract getRequestMethod(req: any): string;
162 | protected indexOf(collection: any[], id: number): number;
163 | /** Parse the id as a number. Return original value if not a number. */
164 | protected parseId(collection: any[], collectionName: string, id: string): any;
165 | /**
166 | * return true if can determine that the collection's `item.id` is a number
167 | * This implementation can't tell if the collection is empty so it assumes NO
168 | * */
169 | protected isCollectionIdNumeric(collection: T[], collectionName: string): boolean;
172 | /**
173 | * Parses the request URL into a `ParsedRequestUrl` object.
174 | * Parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.
175 | *
176 | * Configuring the `apiBase` yields the most interesting changes to `parseRequestUrl` behavior:
177 | * When apiBase=undefined and url='http://localhost/api/collection/42'
178 | * {base: 'api/', collectionName: 'collection', id: '42', ...}
179 | * When apiBase='some/api/root/' and url='http://localhost/some/api/root/collection'
180 | * {base: 'some/api/root/', collectionName: 'collection', id: undefined, ...}
181 | * When apiBase='/' and url='http://localhost/collection'
182 | * {base: '/', collectionName: 'collection', id: undefined, ...}
183 | *
184 | * The actual api base segment values are ignored. Only the number of segments matters.
185 | * The following api base strings are considered identical: 'a/b' ~ 'some/api/' ~ `two/segments'
186 | *
187 | * To replace this default method, assign your alternative to your InMemDbService['parseRequestUrl']
188 | */
189 | protected parseRequestUrl(url: string): ParsedRequestUrl;
190 | protected post({ collection, collectionName, headers, id, req, resourceUrl, url }: RequestInfo): ResponseOptions;
191 | protected put({ collection, collectionName, headers, id, req, url }: RequestInfo): ResponseOptions;
192 | protected removeById(collection: any[], id: number): boolean;
193 | /**
194 | * Tell your in-mem "database" to reset.
195 | * returns Observable of the database because resetting it could be async
196 | */
197 | protected resetDb(reqInfo?: RequestInfo): Observable;
198 | }
199 |
--------------------------------------------------------------------------------
/backend.service.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"BackendService":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":37,"character":30},{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfigArgs","line":38,"character":12}]}],"handleRequest":[{"__symbolic":"method"}],"handleRequest_":[{"__symbolic":"method"}],"addDelay":[{"__symbolic":"method"}],"applyQuery":[{"__symbolic":"method"}],"bind":[{"__symbolic":"method"}],"bodify":[{"__symbolic":"method"}],"clone":[{"__symbolic":"method"}],"collectionHandler":[{"__symbolic":"method"}],"commands":[{"__symbolic":"method"}],"createErrorResponseOptions":[{"__symbolic":"method"}],"createHeaders":[{"__symbolic":"method"}],"createPassThruBackend":[{"__symbolic":"method"}],"createQueryMap":[{"__symbolic":"method"}],"createResponse$":[{"__symbolic":"method"}],"createResponse$fromResponseOptions$":[{"__symbolic":"method"}],"createResponseOptions$":[{"__symbolic":"method"}],"delete":[{"__symbolic":"method"}],"findById":[{"__symbolic":"method"}],"genId":[{"__symbolic":"method"}],"genIdDefault":[{"__symbolic":"method"}],"get":[{"__symbolic":"method"}],"getJsonBody":[{"__symbolic":"method"}],"getLocation":[{"__symbolic":"method"}],"getPassThruBackend":[{"__symbolic":"method"}],"getRequestInfoUtils":[{"__symbolic":"method"}],"getRequestMethod":[{"__symbolic":"method"}],"indexOf":[{"__symbolic":"method"}],"parseId":[{"__symbolic":"method"}],"isCollectionIdNumeric":[{"__symbolic":"method"}],"parseRequestUrl":[{"__symbolic":"method"}],"post":[{"__symbolic":"method"}],"put":[{"__symbolic":"method"}],"removeById":[{"__symbolic":"method"}],"resetDb":[{"__symbolic":"method"}]}}}}]
--------------------------------------------------------------------------------
/delay-response.d.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | /** adds specified delay (in ms) to both next and error channels of the response observable */
3 | export declare function delayResponse(response$: Observable, delayMs: number): Observable;
4 |
--------------------------------------------------------------------------------
/delay-response.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | // Replaces use of RxJS delay. See v0.5.4.
3 | /** adds specified delay (in ms) to both next and error channels of the response observable */
4 | export function delayResponse(response$, delayMs) {
5 | return new Observable(function (observer) {
6 | var completePending = false;
7 | var nextPending = false;
8 | var subscription = response$.subscribe(function (value) {
9 | nextPending = true;
10 | setTimeout(function () {
11 | observer.next(value);
12 | if (completePending) {
13 | observer.complete();
14 | }
15 | }, delayMs);
16 | }, function (error) { return setTimeout(function () { return observer.error(error); }, delayMs); }, function () {
17 | completePending = true;
18 | if (!nextPending) {
19 | observer.complete();
20 | }
21 | });
22 | return function () {
23 | return subscription.unsubscribe();
24 | };
25 | });
26 | }
27 | //# sourceMappingURL=delay-response.js.map
--------------------------------------------------------------------------------
/delay-response.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"delay-response.js","sourceRoot":"","sources":["delay-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,0CAA0C;AAC1C,8FAA8F;AAC9F,MAAM,UAAU,aAAa,CAAI,SAAwB,EAAE,OAAe;IACxE,OAAO,IAAI,UAAU,CAAI,UAAA,QAAQ;QAC/B,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAM,YAAY,GAAG,SAAS,CAAC,SAAS,CACtC,UAAA,KAAK;YACD,WAAW,GAAG,IAAI,CAAC;YACnB,UAAU,CAAC;gBACX,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrB,IAAI,eAAe,EAAE;oBACnB,QAAQ,CAAC,QAAQ,EAAE,CAAC;iBACrB;YACH,CAAC,EAAE,OAAO,CAAC,CAAC;QACd,CAAC,EACD,UAAA,KAAK,IAAI,OAAA,UAAU,CAAC,cAAM,OAAA,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAArB,CAAqB,EAAE,OAAO,CAAC,EAAhD,CAAgD,EACzD;YACE,eAAe,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,WAAW,EAAE;gBAChB,QAAQ,CAAC,QAAQ,EAAE,CAAC;aACrB;QACH,CAAC,CACF,CAAC;QACF,OAAO;YACL,OAAO,YAAY,CAAC,WAAW,EAAE,CAAC;QACpC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { Observable } from 'rxjs';\n\n// Replaces use of RxJS delay. See v0.5.4.\n/** adds specified delay (in ms) to both next and error channels of the response observable */\nexport function delayResponse(response$: Observable, delayMs: number): Observable {\n return new Observable(observer => {\n let completePending = false;\n let nextPending = false;\n const subscription = response$.subscribe(\n value => {\n nextPending = true;\n setTimeout(() => {\n observer.next(value);\n if (completePending) {\n observer.complete();\n }\n }, delayMs);\n },\n error => setTimeout(() => observer.error(error), delayMs),\n () => {\n completePending = true;\n if (!nextPending) {\n observer.complete();\n }\n }\n );\n return () => {\n return subscription.unsubscribe();\n };\n });\n}\n"]}
--------------------------------------------------------------------------------
/delay-response.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"delayResponse":{"__symbolic":"function","parameters":["response$","delayMs"],"value":{"__symbolic":"new","expression":{"__symbolic":"reference","module":"rxjs","name":"Observable","line":5,"character":13},"arguments":[{"__symbolic":"error","message":"Lambda not supported","line":5,"character":27}]}}}}]
--------------------------------------------------------------------------------
/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 | var rollup = require('rollup-stream');
7 | var source = require('vinyl-source-stream');
8 |
9 | var inMemSrc = './src/in-mem/';
10 | var jsCopySrc = ['*.js', '*.js.map', '*.d.ts', '*.metadata.json'].map(ext => inMemSrc + ext);
11 |
12 | gulp.task('help', $.taskListing.withFilters(function (taskName) {
13 | var isSubTask = taskName.substr(0, 1) == "_";
14 | return isSubTask;
15 | }, function (taskName) {
16 | var shouldRemove = taskName === 'default';
17 | return shouldRemove;
18 | }));
19 |
20 | gulp.task('default', gulp.series('help'));
21 |
22 | gulp.task('clean', function() {
23 | return Promise.all([
24 | clean([
25 | 'aot/**/*.*',
26 | 'src/**/*.d.ts',
27 | 'src/**/*.js.map',
28 | 'src/**/*.metadata.json',
29 | 'src/**/*.ngfactory.ts',
30 | 'src/**/*.ngsummary.json'
31 | ]),
32 | clean([
33 | 'src/app/**.*js',
34 | 'src/in-mem/**.*js',
35 | 'src/in-mem/node_modules/**/*.*',
36 | ]),
37 | clean([ /* root-level copies of in-mem web api files */
38 | './backend.service.*',
39 | './http-status-codes.*',
40 | './http-backend.service.*',
41 | './http-client-backend.service.*',
42 | './interfaces.*',
43 | './http-in-memory-web-api.module.*',
44 | './http-client-in-memory-web-api.module.*',
45 | './in-memory-web-api.module.*',
46 | './index.*',
47 | './bundles/in-memory-web-api.umd.js'
48 | ])
49 | ])
50 | .then(() => console.log('Cleaned successfully'));
51 | });
52 |
53 | gulp.task('ngc', gulp.series('clean', function(done) {
54 | runNgc('src/in-mem/', done);
55 | }));
56 |
57 | // Uses rollup-stream plugin https://www.npmjs.com/package/rollup-stream
58 | gulp.task('umd', gulp.series('ngc', function() {
59 | return rollup('rollup.config.js')
60 | .pipe(source('in-memory-web-api.umd.js'))
61 | .pipe(gulp.dest('./bundles'));
62 | }));
63 |
64 | gulp.task('build', gulp.series('umd', function(){
65 | return gulp
66 | .src(jsCopySrc)
67 | .pipe(gulp.dest('./'));
68 | }));
69 |
70 | /**
71 | * Bump the version
72 | * --type=pre will bump the prerelease version *.*.*-x
73 | * --type=patch or no flag will bump the patch version *.*.x
74 | * --type=minor will bump the minor version *.x.*
75 | * --type=major will bump the major version x.*.*
76 | * --version=1.2.3 will bump to a specific version and ignore other flags
77 | */
78 | gulp.task('bump', function() {
79 | var msg = 'Bumping versions';
80 | var type = args.type;
81 | var version = args.ver;
82 | var options = {};
83 | if (version) {
84 | options.version = version;
85 | msg += ' to ' + version;
86 | } else {
87 | options.type = type;
88 | msg += ' for a ' + type;
89 | }
90 | log(msg);
91 |
92 | return gulp
93 | .src('package.json')
94 | // .pipe($.print())
95 | .pipe($.bump(options))
96 | .pipe(gulp.dest('./'));
97 | });
98 | //////////
99 |
100 | function clean(path) {
101 | log('Cleaning: ' + path);
102 | return del(path, {dryRun:false})
103 | .then(function(paths) {
104 | console.log('Deleted files and folders:\n', paths.join('\n'));
105 | });
106 | }
107 |
108 | function log(msg) {
109 | if (typeof(msg) === 'object') {
110 | for (var item in msg) {
111 | if (msg.hasOwnProperty(item)) {
112 | console.log(msg[item]);
113 | }
114 | }
115 | } else {
116 | console.log(msg);
117 | }
118 | }
119 | function runNgc(directory, done) {
120 | directory = directory || './';
121 | //var ngcjs = path.join(process.cwd(), 'node_modules/typescript/bin/tsc');
122 | //ngcjs = path.join(process.cwd(), 'node_modules/.bin/ngc');
123 | var ngcjs = './node_modules/@angular/compiler-cli/src/main.js';
124 | var childProcess = cp.spawn('node', [ngcjs, '-p', './tsconfig-ngc.json'], { cwd: process.cwd() });
125 | childProcess.stdout.on('data', function (data) {
126 | console.log(data.toString());
127 | });
128 | childProcess.stderr.on('data', function (data) {
129 | console.log(data.toString());
130 | });
131 | childProcess.on('close', function (code) {
132 | if (code !== 0) {
133 | throw(new Error('ngc compilation exited with an error code'))
134 | } else {
135 | done();
136 | }
137 | });
138 | }
139 |
--------------------------------------------------------------------------------
/http-client-backend.service.d.ts:
--------------------------------------------------------------------------------
1 | import { HttpBackend, HttpEvent, HttpHeaders, HttpRequest, HttpResponse, HttpXhrBackend, XhrFactory } from '@angular/common/http';
2 | import { Observable } from 'rxjs';
3 | import { InMemoryBackendConfigArgs, InMemoryDbService, ResponseOptions } from './interfaces';
4 | import { BackendService } from './backend.service';
5 | /**
6 | * For Angular `HttpClient` simulate the behavior of a RESTy web api
7 | * backed by the simple in-memory data store provided by the injected `InMemoryDbService`.
8 | * Conforms mostly to behavior described here:
9 | * http://www.restapitutorial.com/lessons/httpmethods.html
10 | *
11 | * ### Usage
12 | *
13 | * Create an in-memory data store class that implements `InMemoryDbService`.
14 | * Call `config` static method with this service class and optional configuration object:
15 | * ```
16 | * // other imports
17 | * import { HttpClientModule } from '@angular/common/http';
18 | * import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
19 | *
20 | * import { InMemHeroService, inMemConfig } from '../api/in-memory-hero.service';
21 | * @NgModule({
22 | * imports: [
23 | * HttpModule,
24 | * HttpClientInMemoryWebApiModule.forRoot(InMemHeroService, inMemConfig),
25 | * ...
26 | * ],
27 | * ...
28 | * })
29 | * export class AppModule { ... }
30 | * ```
31 | */
32 | export declare class HttpClientBackendService extends BackendService implements HttpBackend {
33 | private xhrFactory;
34 | constructor(inMemDbService: InMemoryDbService, config: InMemoryBackendConfigArgs, xhrFactory: XhrFactory);
35 | handle(req: HttpRequest): Observable>;
36 | protected getJsonBody(req: HttpRequest): any;
37 | protected getRequestMethod(req: HttpRequest): string;
38 | protected createHeaders(headers: {
39 | [index: string]: string;
40 | }): HttpHeaders;
41 | protected createQueryMap(search: string): Map;
42 | protected createResponse$fromResponseOptions$(resOptions$: Observable): Observable>;
43 | protected createPassThruBackend(): HttpXhrBackend;
44 | }
45 |
--------------------------------------------------------------------------------
/http-client-backend.service.js:
--------------------------------------------------------------------------------
1 | var __extends = (this && this.__extends) || (function () {
2 | var extendStatics = function (d, b) {
3 | extendStatics = Object.setPrototypeOf ||
4 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 | return extendStatics(d, b);
7 | };
8 | return function (d, b) {
9 | extendStatics(d, b);
10 | function __() { this.constructor = d; }
11 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 | };
13 | })();
14 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
15 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17 | 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;
18 | return c > 3 && r && Object.defineProperty(target, key, r), r;
19 | };
20 | var __metadata = (this && this.__metadata) || function (k, v) {
21 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22 | };
23 | var __param = (this && this.__param) || function (paramIndex, decorator) {
24 | return function (target, key) { decorator(target, key, paramIndex); }
25 | };
26 | import { Inject, Injectable, Optional } from '@angular/core';
27 | import { HttpHeaders, HttpParams, HttpResponse, HttpXhrBackend, XhrFactory } from '@angular/common/http';
28 | import { map } from 'rxjs/operators';
29 | import { STATUS } from './http-status-codes';
30 | import { InMemoryBackendConfig, InMemoryBackendConfigArgs, InMemoryDbService } from './interfaces';
31 | import { BackendService } from './backend.service';
32 | /**
33 | * For Angular `HttpClient` simulate the behavior of a RESTy web api
34 | * backed by the simple in-memory data store provided by the injected `InMemoryDbService`.
35 | * Conforms mostly to behavior described here:
36 | * http://www.restapitutorial.com/lessons/httpmethods.html
37 | *
38 | * ### Usage
39 | *
40 | * Create an in-memory data store class that implements `InMemoryDbService`.
41 | * Call `config` static method with this service class and optional configuration object:
42 | * ```
43 | * // other imports
44 | * import { HttpClientModule } from '@angular/common/http';
45 | * import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
46 | *
47 | * import { InMemHeroService, inMemConfig } from '../api/in-memory-hero.service';
48 | * @NgModule({
49 | * imports: [
50 | * HttpModule,
51 | * HttpClientInMemoryWebApiModule.forRoot(InMemHeroService, inMemConfig),
52 | * ...
53 | * ],
54 | * ...
55 | * })
56 | * export class AppModule { ... }
57 | * ```
58 | */
59 | var HttpClientBackendService = /** @class */ (function (_super) {
60 | __extends(HttpClientBackendService, _super);
61 | function HttpClientBackendService(inMemDbService, config, xhrFactory) {
62 | var _this = _super.call(this, inMemDbService, config) || this;
63 | _this.xhrFactory = xhrFactory;
64 | return _this;
65 | }
66 | HttpClientBackendService.prototype.handle = function (req) {
67 | try {
68 | return this.handleRequest(req);
69 | }
70 | catch (error) {
71 | var err = error.message || error;
72 | var resOptions_1 = this.createErrorResponseOptions(req.url, STATUS.INTERNAL_SERVER_ERROR, "" + err);
73 | return this.createResponse$(function () { return resOptions_1; });
74 | }
75 | };
76 | //// protected overrides /////
77 | HttpClientBackendService.prototype.getJsonBody = function (req) {
78 | return req.body;
79 | };
80 | HttpClientBackendService.prototype.getRequestMethod = function (req) {
81 | return (req.method || 'get').toLowerCase();
82 | };
83 | HttpClientBackendService.prototype.createHeaders = function (headers) {
84 | return new HttpHeaders(headers);
85 | };
86 | HttpClientBackendService.prototype.createQueryMap = function (search) {
87 | var map = new Map();
88 | if (search) {
89 | var params_1 = new HttpParams({ fromString: search });
90 | params_1.keys().forEach(function (p) { return map.set(p, params_1.getAll(p)); });
91 | }
92 | return map;
93 | };
94 | HttpClientBackendService.prototype.createResponse$fromResponseOptions$ = function (resOptions$) {
95 | return resOptions$.pipe(map(function (opts) { return new HttpResponse(opts); }));
96 | };
97 | HttpClientBackendService.prototype.createPassThruBackend = function () {
98 | try {
99 | return new HttpXhrBackend(this.xhrFactory);
100 | }
101 | catch (ex) {
102 | ex.message = 'Cannot create passThru404 backend; ' + (ex.message || '');
103 | throw ex;
104 | }
105 | };
106 | HttpClientBackendService = __decorate([
107 | Injectable(),
108 | __param(1, Inject(InMemoryBackendConfig)), __param(1, Optional()),
109 | __metadata("design:paramtypes", [InMemoryDbService,
110 | InMemoryBackendConfigArgs,
111 | XhrFactory])
112 | ], HttpClientBackendService);
113 | return HttpClientBackendService;
114 | }(BackendService));
115 | export { HttpClientBackendService };
116 | //# sourceMappingURL=http-client-backend.service.js.map
--------------------------------------------------------------------------------
/http-client-backend.service.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"http-client-backend.service.js","sourceRoot":"","sources":["http-client-backend.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAGL,WAAW,EACX,UAAU,EAEV,YAAY,EACZ,cAAc,EACd,UAAU,EACX,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE7C,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EAElB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH;IAA8C,4CAAc;IAE1D,kCACE,cAAiC,EACU,MAAiC,EACpE,UAAsB;QAHhC,YAKE,kBAAM,cAAc,EAAE,MAAM,CAAC,SAC9B;QAHS,gBAAU,GAAV,UAAU,CAAY;;IAGhC,CAAC;IAED,yCAAM,GAAN,UAAO,GAAqB;QAC1B,IAAI;YACF,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;SAEhC;QAAC,OAAO,KAAK,EAAE;YACd,IAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC;YACnC,IAAM,YAAU,GAAG,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,qBAAqB,EAAE,KAAG,GAAK,CAAC,CAAC;YACpG,OAAO,IAAI,CAAC,eAAe,CAAC,cAAM,OAAA,YAAU,EAAV,CAAU,CAAC,CAAC;SAC/C;IACH,CAAC;IAED,+BAA+B;IAErB,8CAAW,GAArB,UAAsB,GAAqB;QACzC,OAAO,GAAG,CAAC,IAAI,CAAC;IAClB,CAAC;IAES,mDAAgB,GAA1B,UAA2B,GAAqB;QAC9C,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7C,CAAC;IAES,gDAAa,GAAvB,UAAwB,OAAqC;QAC3D,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAES,iDAAc,GAAxB,UAAyB,MAAc;QACrC,IAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;QACxC,IAAI,MAAM,EAAE;YACV,IAAM,QAAM,GAAG,IAAI,UAAU,CAAC,EAAC,UAAU,EAAE,MAAM,EAAC,CAAC,CAAC;YACpD,QAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,UAAA,CAAC,IAAI,OAAA,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,QAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAA5B,CAA4B,CAAC,CAAC;SAC1D;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAES,sEAAmC,GAA7C,UAA8C,WAAwC;QACpF,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAC,IAAsB,IAAK,OAAA,IAAI,YAAY,CAAM,IAAI,CAAC,EAA3B,CAA2B,CAAC,CAAC,CAAC;IACxF,CAAC;IAES,wDAAqB,GAA/B;QACE,IAAI;YACF,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAC5C;QAAC,OAAO,EAAE,EAAE;YACX,EAAE,CAAC,OAAO,GAAG,qCAAqC,GAAG,CAAC,EAAE,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YACxE,MAAM,EAAE,CAAC;SACV;IACH,CAAC;IAvDU,wBAAwB;QADpC,UAAU,EAAE;QAKR,WAAA,MAAM,CAAC,qBAAqB,CAAC,CAAA,EAAE,WAAA,QAAQ,EAAE,CAAA;yCAD1B,iBAAiB;YACkB,yBAAyB;YACxD,UAAU;OALrB,wBAAwB,CAwDpC;IAAD,+BAAC;CAAA,AAxDD,CAA8C,cAAc,GAwD3D;SAxDY,wBAAwB","sourcesContent":["import { Inject, Injectable, Optional } from '@angular/core';\nimport {\n HttpBackend,\n HttpEvent,\n HttpHeaders,\n HttpParams,\n HttpRequest,\n HttpResponse, HttpResponseBase,\n HttpXhrBackend,\n XhrFactory\n} from '@angular/common/http';\n\nimport { Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { STATUS } from './http-status-codes';\n\nimport {\n InMemoryBackendConfig,\n InMemoryBackendConfigArgs,\n InMemoryDbService,\n ResponseOptions\n} from './interfaces';\n\nimport { BackendService } from './backend.service';\n\n/**\n * For Angular `HttpClient` simulate the behavior of a RESTy web api\n * backed by the simple in-memory data store provided by the injected `InMemoryDbService`.\n * Conforms mostly to behavior described here:\n * http://www.restapitutorial.com/lessons/httpmethods.html\n *\n * ### Usage\n *\n * Create an in-memory data store class that implements `InMemoryDbService`.\n * Call `config` static method with this service class and optional configuration object:\n * ```\n * // other imports\n * import { HttpClientModule } from '@angular/common/http';\n * import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';\n *\n * import { InMemHeroService, inMemConfig } from '../api/in-memory-hero.service';\n * @NgModule({\n * imports: [\n * HttpModule,\n * HttpClientInMemoryWebApiModule.forRoot(InMemHeroService, inMemConfig),\n * ...\n * ],\n * ...\n * })\n * export class AppModule { ... }\n * ```\n */\n@Injectable()\nexport class HttpClientBackendService extends BackendService implements HttpBackend {\n\n constructor(\n inMemDbService: InMemoryDbService,\n @Inject(InMemoryBackendConfig) @Optional() config: InMemoryBackendConfigArgs,\n private xhrFactory: XhrFactory\n ) {\n super(inMemDbService, config);\n }\n\n handle(req: HttpRequest): Observable> {\n try {\n return this.handleRequest(req);\n\n } catch (error) {\n const err = error.message || error;\n const resOptions = this.createErrorResponseOptions(req.url, STATUS.INTERNAL_SERVER_ERROR, `${err}`);\n return this.createResponse$(() => resOptions);\n }\n }\n\n //// protected overrides /////\n\n protected getJsonBody(req: HttpRequest): any {\n return req.body;\n }\n\n protected getRequestMethod(req: HttpRequest): string {\n return (req.method || 'get').toLowerCase();\n }\n\n protected createHeaders(headers: { [index: string]: string; }): HttpHeaders {\n return new HttpHeaders(headers);\n }\n\n protected createQueryMap(search: string): Map {\n const map = new Map();\n if (search) {\n const params = new HttpParams({fromString: search});\n params.keys().forEach(p => map.set(p, params.getAll(p)));\n }\n return map;\n }\n\n protected createResponse$fromResponseOptions$(resOptions$: Observable): Observable> {\n return resOptions$.pipe(map((opts: HttpResponseBase) => new HttpResponse(opts)));\n }\n\n protected createPassThruBackend() {\n try {\n return new HttpXhrBackend(this.xhrFactory);\n } catch (ex) {\n ex.message = 'Cannot create passThru404 backend; ' + (ex.message || '');\n throw ex;\n }\n }\n}\n"]}
--------------------------------------------------------------------------------
/http-client-backend.service.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"HttpClientBackendService":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"./backend.service","name":"BackendService","line":54,"character":46},"decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Injectable","line":53,"character":1}}],"members":{"__ctor__":[{"__symbolic":"constructor","parameterDecorators":[null,[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Inject","line":58,"character":5},"arguments":[{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfig","line":58,"character":12}]},{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Optional","line":58,"character":36}}],null],"parameters":[{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":57,"character":20},{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfigArgs","line":58,"character":55},{"__symbolic":"reference","module":"@angular/common/http","name":"XhrFactory","line":59,"character":24}]}],"handle":[{"__symbolic":"method"}],"getJsonBody":[{"__symbolic":"method"}],"getRequestMethod":[{"__symbolic":"method"}],"createHeaders":[{"__symbolic":"method"}],"createQueryMap":[{"__symbolic":"method"}],"createResponse$fromResponseOptions$":[{"__symbolic":"method"}],"createPassThruBackend":[{"__symbolic":"method"}]}}}}]
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.d.ts:
--------------------------------------------------------------------------------
1 | import { ModuleWithProviders, Type } from '@angular/core';
2 | import { HttpBackend, XhrFactory } from '@angular/common/http';
3 | import { InMemoryBackendConfigArgs, InMemoryBackendConfig, InMemoryDbService } from './interfaces';
4 | export declare function httpClientInMemBackendServiceFactory(dbService: InMemoryDbService, options: InMemoryBackendConfig, xhrFactory: XhrFactory): HttpBackend;
5 | export declare class HttpClientInMemoryWebApiModule {
6 | /**
7 | * Redirect the Angular `HttpClient` XHR calls
8 | * to in-memory data store that implements `InMemoryDbService`.
9 | * with class that implements InMemoryDbService and creates an in-memory database.
10 | *
11 | * Usually imported in the root application module.
12 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
13 | *
14 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
15 | * @param {InMemoryBackendConfigArgs} [options]
16 | *
17 | * @example
18 | * HttpInMemoryWebApiModule.forRoot(dbCreator);
19 | * HttpInMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
20 | */
21 | static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders;
22 | /**
23 | *
24 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
25 | * Same as `forRoot`.
26 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
27 | */
28 | static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders;
29 | }
30 |
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.js:
--------------------------------------------------------------------------------
1 | ////// HttpClient-Only version ////
2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5 | 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;
6 | return c > 3 && r && Object.defineProperty(target, key, r), r;
7 | };
8 | import { NgModule } from '@angular/core';
9 | import { HttpBackend, XhrFactory } from '@angular/common/http';
10 | import { InMemoryBackendConfig, InMemoryDbService } from './interfaces';
11 | import { HttpClientBackendService } from './http-client-backend.service';
12 | // Internal - Creates the in-mem backend for the HttpClient module
13 | // AoT requires factory to be exported
14 | export function httpClientInMemBackendServiceFactory(dbService, options, xhrFactory) {
15 | var backend = new HttpClientBackendService(dbService, options, xhrFactory);
16 | return backend;
17 | }
18 | var HttpClientInMemoryWebApiModule = /** @class */ (function () {
19 | function HttpClientInMemoryWebApiModule() {
20 | }
21 | HttpClientInMemoryWebApiModule_1 = HttpClientInMemoryWebApiModule;
22 | /**
23 | * Redirect the Angular `HttpClient` XHR calls
24 | * to in-memory data store that implements `InMemoryDbService`.
25 | * with class that implements InMemoryDbService and creates an in-memory database.
26 | *
27 | * Usually imported in the root application module.
28 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
29 | *
30 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
31 | * @param {InMemoryBackendConfigArgs} [options]
32 | *
33 | * @example
34 | * HttpInMemoryWebApiModule.forRoot(dbCreator);
35 | * HttpInMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
36 | */
37 | HttpClientInMemoryWebApiModule.forRoot = function (dbCreator, options) {
38 | return {
39 | ngModule: HttpClientInMemoryWebApiModule_1,
40 | providers: [
41 | { provide: InMemoryDbService, useClass: dbCreator },
42 | { provide: InMemoryBackendConfig, useValue: options },
43 | { provide: HttpBackend,
44 | useFactory: httpClientInMemBackendServiceFactory,
45 | deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory] }
46 | ]
47 | };
48 | };
49 | /**
50 | *
51 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
52 | * Same as `forRoot`.
53 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
54 | */
55 | HttpClientInMemoryWebApiModule.forFeature = function (dbCreator, options) {
56 | return HttpClientInMemoryWebApiModule_1.forRoot(dbCreator, options);
57 | };
58 | var HttpClientInMemoryWebApiModule_1;
59 | HttpClientInMemoryWebApiModule = HttpClientInMemoryWebApiModule_1 = __decorate([
60 | NgModule({})
61 | ], HttpClientInMemoryWebApiModule);
62 | return HttpClientInMemoryWebApiModule;
63 | }());
64 | export { HttpClientInMemoryWebApiModule };
65 | //# sourceMappingURL=http-client-in-memory-web-api.module.js.map
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"http-client-in-memory-web-api.module.js","sourceRoot":"","sources":["http-client-in-memory-web-api.module.ts"],"names":[],"mappings":"AAAA,mCAAmC;;;;;;;AAEnC,OAAO,EAAE,QAAQ,EAA6B,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAEL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,kEAAkE;AAClE,sCAAsC;AACtC,MAAM,UAAU,oCAAoC,CAClD,SAA4B,EAC5B,OAA8B,EAC9B,UAAsB;IAEtB,IAAM,OAAO,GAAQ,IAAI,wBAAwB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAClF,OAAO,OAAO,CAAC;AACjB,CAAC;AAGD;IAAA;IAwCA,CAAC;uCAxCY,8BAA8B;IACzC;;;;;;;;;;;;;;MAcE;IACK,sCAAO,GAAd,UAAe,SAAkC,EAAE,OAAmC;QAEpF,OAAO;YACL,QAAQ,EAAE,gCAA8B;YACxC,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,iBAAiB,EAAG,QAAQ,EAAE,SAAS,EAAE;gBACpD,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAErD,EAAE,OAAO,EAAE,WAAW;oBACpB,UAAU,EAAE,oCAAoC;oBAChD,IAAI,EAAE,CAAC,iBAAiB,EAAE,qBAAqB,EAAE,UAAU,CAAC,EAAC;aAChE;SACF,CAAC;IACJ,CAAC;IACC;;;;;KAKC;IACI,yCAAU,GAAjB,UAAkB,SAAkC,EAAE,OAAmC;QAEvF,OAAO,gCAA8B,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACpE,CAAC;;IAvCU,8BAA8B;QAD1C,QAAQ,CAAC,EAAE,CAAC;OACA,8BAA8B,CAwC1C;IAAD,qCAAC;CAAA,AAxCD,IAwCC;SAxCY,8BAA8B","sourcesContent":["////// HttpClient-Only version ////\n\nimport { NgModule, ModuleWithProviders, Type } from '@angular/core';\nimport { HttpBackend, XhrFactory } from '@angular/common/http';\n\nimport {\n InMemoryBackendConfigArgs,\n InMemoryBackendConfig,\n InMemoryDbService\n} from './interfaces';\n\nimport { HttpClientBackendService } from './http-client-backend.service';\n\n// Internal - Creates the in-mem backend for the HttpClient module\n// AoT requires factory to be exported\nexport function httpClientInMemBackendServiceFactory(\n dbService: InMemoryDbService,\n options: InMemoryBackendConfig,\n xhrFactory: XhrFactory,\n): HttpBackend {\n const backend: any = new HttpClientBackendService(dbService, options, xhrFactory);\n return backend;\n}\n\n@NgModule({})\nexport class HttpClientInMemoryWebApiModule {\n /**\n * Redirect the Angular `HttpClient` XHR calls\n * to in-memory data store that implements `InMemoryDbService`.\n * with class that implements InMemoryDbService and creates an in-memory database.\n *\n * Usually imported in the root application module.\n * Can import in a lazy feature module too, which will shadow modules loaded earlier\n *\n * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.\n * @param {InMemoryBackendConfigArgs} [options]\n *\n * @example\n * HttpInMemoryWebApiModule.forRoot(dbCreator);\n * HttpInMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});\n */\n static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs):\n ModuleWithProviders {\n return {\n ngModule: HttpClientInMemoryWebApiModule,\n providers: [\n { provide: InMemoryDbService, useClass: dbCreator },\n { provide: InMemoryBackendConfig, useValue: options },\n\n { provide: HttpBackend,\n useFactory: httpClientInMemBackendServiceFactory,\n deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory]}\n ]\n };\n }\n /**\n *\n * Enable and configure the in-memory web api in a lazy-loaded feature module.\n * Same as `forRoot`.\n * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.\n */\n static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs):\n ModuleWithProviders {\n return HttpClientInMemoryWebApiModule.forRoot(dbCreator, options);\n }\n}\n"]}
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"httpClientInMemBackendServiceFactory":{"__symbolic":"function"},"HttpClientInMemoryWebApiModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":24,"character":1},"arguments":[{}]}],"statics":{"forRoot":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"ngModule":{"__symbolic":"reference","name":"HttpClientInMemoryWebApiModule"},"providers":[{"provide":{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":46,"character":19},"useClass":{"__symbolic":"reference","name":"dbCreator"}},{"provide":{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfig","line":47,"character":19},"useValue":{"__symbolic":"reference","name":"options"}},{"provide":{"__symbolic":"reference","module":"@angular/common/http","name":"HttpBackend","line":49,"character":19},"useFactory":{"__symbolic":"reference","name":"httpClientInMemBackendServiceFactory"},"deps":[{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":51,"character":17},{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfig","line":51,"character":36},{"__symbolic":"reference","module":"@angular/common/http","name":"XhrFactory","line":51,"character":59}]}]}},"forFeature":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbolic":"reference","name":"HttpClientInMemoryWebApiModule"},"member":"forRoot"},"arguments":[{"__symbolic":"reference","name":"dbCreator"},{"__symbolic":"reference","name":"options"}]}}}}}}]
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.ngfactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as i0 from '@angular/core';
2 | import * as i1 from './http-client-in-memory-web-api.module';
3 | export declare const HttpClientInMemoryWebApiModuleNgFactory: i0.NgModuleFactory;
4 |
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.ngfactory.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview This file was generated by the Angular template compiler. Do not edit.
3 | *
4 | * @suppress {suspiciousCode,uselessCode,missingProperties,missingOverride,checkTypes}
5 | * tslint:disable
6 | */
7 | import * as i0 from "@angular/core";
8 | import * as i1 from "./http-client-in-memory-web-api.module";
9 | var HttpClientInMemoryWebApiModuleNgFactory = i0.ɵcmf(i1.HttpClientInMemoryWebApiModule, [], function (_l) { return i0.ɵmod([i0.ɵmpd(512, i0.ComponentFactoryResolver, i0.ɵCodegenComponentFactoryResolver, [[8, []], [3, i0.ComponentFactoryResolver], i0.NgModuleRef]), i0.ɵmpd(1073742336, i1.HttpClientInMemoryWebApiModule, i1.HttpClientInMemoryWebApiModule, [])]); });
10 | export { HttpClientInMemoryWebApiModuleNgFactory as HttpClientInMemoryWebApiModuleNgFactory };
11 | //# sourceMappingURL=http-client-in-memory-web-api.module.ngfactory.js.map
--------------------------------------------------------------------------------
/http-client-in-memory-web-api.module.ngfactory.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"http-client-in-memory-web-api.module.ngfactory.js","sourceRoot":"","sources":["http-client-in-memory-web-api.module.ngfactory.ts"],"names":[],"mappings":"","sourcesContent":["import * as i0 from '@angular/core';\nimport * as i1 from './http-client-in-memory-web-api.module';\nexport const HttpClientInMemoryWebApiModuleNgFactory:i0.NgModuleFactory = (null as any);\nvar _decl0_0:i0.TemplateRef = ((null as any));\nvar _decl0_1:i0.ElementRef = ((null as any));\n"]}
--------------------------------------------------------------------------------
/http-status-codes.d.ts:
--------------------------------------------------------------------------------
1 | export declare const 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 const 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 | '200': {
75 | 'code': number;
76 | 'text': string;
77 | 'description': string;
78 | 'spec_title': string;
79 | 'spec_href': string;
80 | };
81 | '201': {
82 | 'code': number;
83 | 'text': string;
84 | 'description': string;
85 | 'spec_title': string;
86 | 'spec_href': string;
87 | };
88 | '202': {
89 | 'code': number;
90 | 'text': string;
91 | 'description': string;
92 | 'spec_title': string;
93 | 'spec_href': string;
94 | };
95 | '203': {
96 | 'code': number;
97 | 'text': string;
98 | 'description': string;
99 | 'spec_title': string;
100 | 'spec_href': string;
101 | };
102 | '204': {
103 | 'code': number;
104 | 'text': string;
105 | 'description': string;
106 | 'spec_title': string;
107 | 'spec_href': string;
108 | };
109 | '205': {
110 | 'code': number;
111 | 'text': string;
112 | 'description': string;
113 | 'spec_title': string;
114 | 'spec_href': string;
115 | };
116 | '206': {
117 | 'code': number;
118 | 'text': string;
119 | 'description': string;
120 | 'spec_title': string;
121 | 'spec_href': string;
122 | };
123 | '300': {
124 | 'code': number;
125 | 'text': string;
126 | 'description': string;
127 | 'spec_title': string;
128 | 'spec_href': string;
129 | };
130 | '301': {
131 | 'code': number;
132 | 'text': string;
133 | 'description': string;
134 | 'spec_title': string;
135 | 'spec_href': string;
136 | };
137 | '302': {
138 | 'code': number;
139 | 'text': string;
140 | 'description': string;
141 | 'spec_title': string;
142 | 'spec_href': string;
143 | };
144 | '303': {
145 | 'code': number;
146 | 'text': string;
147 | 'description': string;
148 | 'spec_title': string;
149 | 'spec_href': string;
150 | };
151 | '304': {
152 | 'code': number;
153 | 'text': string;
154 | 'description': string;
155 | 'spec_title': string;
156 | 'spec_href': string;
157 | };
158 | '305': {
159 | 'code': number;
160 | 'text': string;
161 | 'description': string;
162 | 'spec_title': string;
163 | 'spec_href': string;
164 | };
165 | '307': {
166 | 'code': number;
167 | 'text': string;
168 | 'description': string;
169 | 'spec_title': string;
170 | 'spec_href': string;
171 | };
172 | '400': {
173 | 'code': number;
174 | 'text': string;
175 | 'description': string;
176 | 'spec_title': string;
177 | 'spec_href': string;
178 | };
179 | '401': {
180 | 'code': number;
181 | 'text': string;
182 | 'description': string;
183 | 'spec_title': string;
184 | 'spec_href': string;
185 | };
186 | '402': {
187 | 'code': number;
188 | 'text': string;
189 | 'description': string;
190 | 'spec_title': string;
191 | 'spec_href': string;
192 | };
193 | '403': {
194 | 'code': number;
195 | 'text': string;
196 | 'description': string;
197 | 'spec_title': string;
198 | 'spec_href': string;
199 | };
200 | '404': {
201 | 'code': number;
202 | 'text': string;
203 | 'description': string;
204 | 'spec_title': string;
205 | 'spec_href': string;
206 | };
207 | '405': {
208 | 'code': number;
209 | 'text': string;
210 | 'description': string;
211 | 'spec_title': string;
212 | 'spec_href': string;
213 | };
214 | '406': {
215 | 'code': number;
216 | 'text': string;
217 | 'description': string;
218 | 'spec_title': string;
219 | 'spec_href': string;
220 | };
221 | '407': {
222 | 'code': number;
223 | 'text': string;
224 | 'description': string;
225 | 'spec_title': string;
226 | 'spec_href': string;
227 | };
228 | '408': {
229 | 'code': number;
230 | 'text': string;
231 | 'description': string;
232 | 'spec_title': string;
233 | 'spec_href': string;
234 | };
235 | '409': {
236 | 'code': number;
237 | 'text': string;
238 | 'description': string;
239 | 'spec_title': string;
240 | 'spec_href': string;
241 | };
242 | '410': {
243 | 'code': number;
244 | 'text': string;
245 | 'description': string;
246 | 'spec_title': string;
247 | 'spec_href': string;
248 | };
249 | '411': {
250 | 'code': number;
251 | 'text': string;
252 | 'description': string;
253 | 'spec_title': string;
254 | 'spec_href': string;
255 | };
256 | '412': {
257 | 'code': number;
258 | 'text': string;
259 | 'description': string;
260 | 'spec_title': string;
261 | 'spec_href': string;
262 | };
263 | '413': {
264 | 'code': number;
265 | 'text': string;
266 | 'description': string;
267 | 'spec_title': string;
268 | 'spec_href': string;
269 | };
270 | '414': {
271 | 'code': number;
272 | 'text': string;
273 | 'description': string;
274 | 'spec_title': string;
275 | 'spec_href': string;
276 | };
277 | '415': {
278 | 'code': number;
279 | 'text': string;
280 | 'description': string;
281 | 'spec_title': string;
282 | 'spec_href': string;
283 | };
284 | '416': {
285 | 'code': number;
286 | 'text': string;
287 | 'description': string;
288 | 'spec_title': string;
289 | 'spec_href': string;
290 | };
291 | '417': {
292 | 'code': number;
293 | 'text': string;
294 | 'description': string;
295 | 'spec_title': string;
296 | 'spec_href': string;
297 | };
298 | '418': {
299 | 'code': number;
300 | 'text': string;
301 | 'description': string;
302 | 'spec_title': string;
303 | 'spec_href': string;
304 | };
305 | '426': {
306 | 'code': number;
307 | 'text': string;
308 | 'description': string;
309 | 'spec_title': string;
310 | 'spec_href': string;
311 | };
312 | '500': {
313 | 'code': number;
314 | 'text': string;
315 | 'description': string;
316 | 'spec_title': string;
317 | 'spec_href': string;
318 | };
319 | '501': {
320 | 'code': number;
321 | 'text': string;
322 | 'description': string;
323 | 'spec_title': string;
324 | 'spec_href': string;
325 | };
326 | '502': {
327 | 'code': number;
328 | 'text': string;
329 | 'description': string;
330 | 'spec_title': string;
331 | 'spec_href': string;
332 | };
333 | '503': {
334 | 'code': number;
335 | 'text': string;
336 | 'description': string;
337 | 'spec_title': string;
338 | 'spec_href': string;
339 | };
340 | '504': {
341 | 'code': number;
342 | 'text': string;
343 | 'description': string;
344 | 'spec_title': string;
345 | 'spec_href': string;
346 | };
347 | '505': {
348 | 'code': number;
349 | 'text': string;
350 | 'description': string;
351 | 'spec_title': string;
352 | 'spec_href': string;
353 | };
354 | '102': {
355 | 'code': number;
356 | 'text': string;
357 | 'description': string;
358 | 'spec_title': string;
359 | 'spec_href': string;
360 | };
361 | '207': {
362 | 'code': number;
363 | 'text': string;
364 | 'description': string;
365 | 'spec_title': string;
366 | 'spec_href': string;
367 | };
368 | '226': {
369 | 'code': number;
370 | 'text': string;
371 | 'description': string;
372 | 'spec_title': string;
373 | 'spec_href': string;
374 | };
375 | '308': {
376 | 'code': number;
377 | 'text': string;
378 | 'description': string;
379 | 'spec_title': string;
380 | 'spec_href': string;
381 | };
382 | '422': {
383 | 'code': number;
384 | 'text': string;
385 | 'description': string;
386 | 'spec_title': string;
387 | 'spec_href': string;
388 | };
389 | '423': {
390 | 'code': number;
391 | 'text': string;
392 | 'description': string;
393 | 'spec_title': string;
394 | 'spec_href': string;
395 | };
396 | '424': {
397 | 'code': number;
398 | 'text': string;
399 | 'description': string;
400 | 'spec_title': string;
401 | 'spec_href': string;
402 | };
403 | '428': {
404 | 'code': number;
405 | 'text': string;
406 | 'description': string;
407 | 'spec_title': string;
408 | 'spec_href': string;
409 | };
410 | '429': {
411 | 'code': number;
412 | 'text': string;
413 | 'description': string;
414 | 'spec_title': string;
415 | 'spec_href': string;
416 | };
417 | '431': {
418 | 'code': number;
419 | 'text': string;
420 | 'description': string;
421 | 'spec_title': string;
422 | 'spec_href': string;
423 | };
424 | '451': {
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 | /**
454 | * get the status text from StatusCode
455 | */
456 | export declare function getStatusText(status: number): any;
457 | /**
458 | * Returns true if the the Http Status Code is 200-299 (success)
459 | */
460 | export declare function isSuccess(status: number): boolean;
461 |
--------------------------------------------------------------------------------
/in-memory-web-api.module.d.ts:
--------------------------------------------------------------------------------
1 | import { ModuleWithProviders, Type } from '@angular/core';
2 | import { InMemoryBackendConfigArgs, InMemoryDbService } from './interfaces';
3 | export declare class InMemoryWebApiModule {
4 | /**
5 | * Redirect BOTH Angular `Http` and `HttpClient` XHR calls
6 | * to in-memory data store that implements `InMemoryDbService`.
7 | * with class that implements InMemoryDbService and creates an in-memory database.
8 | *
9 | * Usually imported in the root application module.
10 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
11 | *
12 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
13 | * @param {InMemoryBackendConfigArgs} [options]
14 | *
15 | * @example
16 | * InMemoryWebApiModule.forRoot(dbCreator);
17 | * InMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
18 | */
19 | static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders;
20 | /**
21 | *
22 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
23 | * Same as `forRoot`.
24 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
25 | */
26 | static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders;
27 | }
28 |
--------------------------------------------------------------------------------
/in-memory-web-api.module.js:
--------------------------------------------------------------------------------
1 | ////// For apps with both Http and HttpClient ////
2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5 | 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;
6 | return c > 3 && r && Object.defineProperty(target, key, r), r;
7 | };
8 | import { NgModule } from '@angular/core';
9 | import { HttpBackend, XhrFactory } from '@angular/common/http';
10 | import { InMemoryBackendConfig, InMemoryDbService } from './interfaces';
11 | import { httpClientInMemBackendServiceFactory } from './http-client-in-memory-web-api.module';
12 | var InMemoryWebApiModule = /** @class */ (function () {
13 | function InMemoryWebApiModule() {
14 | }
15 | InMemoryWebApiModule_1 = InMemoryWebApiModule;
16 | /**
17 | * Redirect BOTH Angular `Http` and `HttpClient` XHR calls
18 | * to in-memory data store that implements `InMemoryDbService`.
19 | * with class that implements InMemoryDbService and creates an in-memory database.
20 | *
21 | * Usually imported in the root application module.
22 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
23 | *
24 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
25 | * @param {InMemoryBackendConfigArgs} [options]
26 | *
27 | * @example
28 | * InMemoryWebApiModule.forRoot(dbCreator);
29 | * InMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
30 | */
31 | InMemoryWebApiModule.forRoot = function (dbCreator, options) {
32 | return {
33 | ngModule: InMemoryWebApiModule_1,
34 | providers: [
35 | { provide: InMemoryDbService, useClass: dbCreator },
36 | { provide: InMemoryBackendConfig, useValue: options },
37 | { provide: HttpBackend,
38 | useFactory: httpClientInMemBackendServiceFactory,
39 | deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory] }
40 | ]
41 | };
42 | };
43 | /**
44 | *
45 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
46 | * Same as `forRoot`.
47 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
48 | */
49 | InMemoryWebApiModule.forFeature = function (dbCreator, options) {
50 | return InMemoryWebApiModule_1.forRoot(dbCreator, options);
51 | };
52 | var InMemoryWebApiModule_1;
53 | InMemoryWebApiModule = InMemoryWebApiModule_1 = __decorate([
54 | NgModule({})
55 | ], InMemoryWebApiModule);
56 | return InMemoryWebApiModule;
57 | }());
58 | export { InMemoryWebApiModule };
59 | //# sourceMappingURL=in-memory-web-api.module.js.map
--------------------------------------------------------------------------------
/in-memory-web-api.module.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"in-memory-web-api.module.js","sourceRoot":"","sources":["in-memory-web-api.module.ts"],"names":[],"mappings":"AAAA,kDAAkD;;;;;;;AAElD,OAAO,EAAY,QAAQ,EAA6B,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAEL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,oCAAoC,EAAE,MAAM,wCAAwC,CAAC;AAG9F;IAAA;IAwCA,CAAC;6BAxCY,oBAAoB;IAC/B;;;;;;;;;;;;;;MAcE;IACK,4BAAO,GAAd,UAAe,SAAkC,EAAE,OAAmC;QACpF,OAAO;YACL,QAAQ,EAAE,sBAAoB;YAC9B,SAAS,EAAE;gBACT,EAAE,OAAO,EAAE,iBAAiB,EAAG,QAAQ,EAAE,SAAS,EAAE;gBACpD,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,OAAO,EAAE;gBAGrD,EAAE,OAAO,EAAE,WAAW;oBACpB,UAAU,EAAE,oCAAoC;oBAChD,IAAI,EAAE,CAAC,iBAAiB,EAAE,qBAAqB,EAAE,UAAU,CAAC,EAAC;aAChE;SACF,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACI,+BAAU,GAAjB,UAAkB,SAAkC,EAAE,OAAmC;QACvF,OAAO,sBAAoB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1D,CAAC;;IAvCU,oBAAoB;QADhC,QAAQ,CAAC,EAAE,CAAC;OACA,oBAAoB,CAwChC;IAAD,2BAAC;CAAA,AAxCD,IAwCC;SAxCY,oBAAoB","sourcesContent":["////// For apps with both Http and HttpClient ////\n\nimport { Injector, NgModule, ModuleWithProviders, Type } from '@angular/core';\nimport { HttpBackend, XhrFactory } from '@angular/common/http';\n\nimport {\n InMemoryBackendConfigArgs,\n InMemoryBackendConfig,\n InMemoryDbService\n} from './interfaces';\n\nimport { httpClientInMemBackendServiceFactory } from './http-client-in-memory-web-api.module';\n\n@NgModule({})\nexport class InMemoryWebApiModule {\n /**\n * Redirect BOTH Angular `Http` and `HttpClient` XHR calls\n * to in-memory data store that implements `InMemoryDbService`.\n * with class that implements InMemoryDbService and creates an in-memory database.\n *\n * Usually imported in the root application module.\n * Can import in a lazy feature module too, which will shadow modules loaded earlier\n *\n * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.\n * @param {InMemoryBackendConfigArgs} [options]\n *\n * @example\n * InMemoryWebApiModule.forRoot(dbCreator);\n * InMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});\n */\n static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders {\n return {\n ngModule: InMemoryWebApiModule,\n providers: [\n { provide: InMemoryDbService, useClass: dbCreator },\n { provide: InMemoryBackendConfig, useValue: options },\n\n\n { provide: HttpBackend,\n useFactory: httpClientInMemBackendServiceFactory,\n deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory]}\n ]\n };\n }\n\n /**\n *\n * Enable and configure the in-memory web api in a lazy-loaded feature module.\n * Same as `forRoot`.\n * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.\n */\n static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders {\n return InMemoryWebApiModule.forRoot(dbCreator, options);\n }\n}\n"]}
--------------------------------------------------------------------------------
/in-memory-web-api.module.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"InMemoryWebApiModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":13,"character":1},"arguments":[{}]}],"statics":{"forRoot":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"ngModule":{"__symbolic":"reference","name":"InMemoryWebApiModule"},"providers":[{"provide":{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":34,"character":19},"useClass":{"__symbolic":"reference","name":"dbCreator"}},{"provide":{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfig","line":35,"character":19},"useValue":{"__symbolic":"reference","name":"options"}},{"provide":{"__symbolic":"reference","module":"@angular/common/http","name":"HttpBackend","line":38,"character":19},"useFactory":{"__symbolic":"reference","module":"./http-client-in-memory-web-api.module","name":"httpClientInMemBackendServiceFactory","line":39,"character":22},"deps":[{"__symbolic":"reference","module":"./interfaces","name":"InMemoryDbService","line":40,"character":17},{"__symbolic":"reference","module":"./interfaces","name":"InMemoryBackendConfig","line":40,"character":36},{"__symbolic":"reference","module":"@angular/common/http","name":"XhrFactory","line":40,"character":59}]}]}},"forFeature":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbolic":"reference","name":"InMemoryWebApiModule"},"member":"forRoot"},"arguments":[{"__symbolic":"reference","name":"dbCreator"},{"__symbolic":"reference","name":"options"}]}}}}}}]
--------------------------------------------------------------------------------
/in-memory-web-api.module.ngfactory.d.ts:
--------------------------------------------------------------------------------
1 | import * as i0 from '@angular/core';
2 | import * as i1 from './in-memory-web-api.module';
3 | export declare const InMemoryWebApiModuleNgFactory: i0.NgModuleFactory;
4 |
--------------------------------------------------------------------------------
/in-memory-web-api.module.ngfactory.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview This file was generated by the Angular template compiler. Do not edit.
3 | *
4 | * @suppress {suspiciousCode,uselessCode,missingProperties,missingOverride,checkTypes}
5 | * tslint:disable
6 | */
7 | import * as i0 from "@angular/core";
8 | import * as i1 from "./in-memory-web-api.module";
9 | var InMemoryWebApiModuleNgFactory = i0.ɵcmf(i1.InMemoryWebApiModule, [], function (_l) { return i0.ɵmod([i0.ɵmpd(512, i0.ComponentFactoryResolver, i0.ɵCodegenComponentFactoryResolver, [[8, []], [3, i0.ComponentFactoryResolver], i0.NgModuleRef]), i0.ɵmpd(1073742336, i1.InMemoryWebApiModule, i1.InMemoryWebApiModule, [])]); });
10 | export { InMemoryWebApiModuleNgFactory as InMemoryWebApiModuleNgFactory };
11 | //# sourceMappingURL=in-memory-web-api.module.ngfactory.js.map
--------------------------------------------------------------------------------
/in-memory-web-api.module.ngfactory.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"in-memory-web-api.module.ngfactory.js","sourceRoot":"","sources":["in-memory-web-api.module.ngfactory.ts"],"names":[],"mappings":"","sourcesContent":["import * as i0 from '@angular/core';\nimport * as i1 from './in-memory-web-api.module';\nexport const InMemoryWebApiModuleNgFactory:i0.NgModuleFactory = (null as any);\nvar _decl0_0:i0.TemplateRef = ((null as any));\nvar _decl0_1:i0.ElementRef = ((null as any));\n"]}
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from './backend.service';
2 | export * from './http-status-codes';
3 | export * from './http-client-backend.service';
4 | export * from './in-memory-web-api.module';
5 | export * from './http-client-in-memory-web-api.module';
6 | export * from './interfaces';
7 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | export * from './backend.service';
2 | export * from './http-status-codes';
3 | export * from './http-client-backend.service';
4 | export * from './in-memory-web-api.module';
5 | export * from './http-client-in-memory-web-api.module';
6 | export * from './interfaces';
7 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wCAAwC,CAAC;AACvD,cAAc,cAAc,CAAC","sourcesContent":["export * from './backend.service';\nexport * from './http-status-codes';\nexport * from './http-client-backend.service';\nexport * from './in-memory-web-api.module';\nexport * from './http-client-in-memory-web-api.module';\nexport * from './interfaces';\n"]}
--------------------------------------------------------------------------------
/index.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{},"exports":[{"from":"./backend.service"},{"from":"./http-status-codes"},{"from":"./http-client-backend.service"},{"from":"./in-memory-web-api.module"},{"from":"./http-client-in-memory-web-api.module"},{"from":"./interfaces"}]}]
--------------------------------------------------------------------------------
/interfaces.d.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | /**
3 | * Minimum definition needed by base class
4 | */
5 | export interface HeadersCore {
6 | set(name: string, value: string): void | any;
7 | }
8 | /**
9 | * Interface for a class that creates an in-memory database
10 | *
11 | * Its `createDb` method creates a hash of named collections that represents the database
12 | *
13 | * For maximum flexibility, the service may define HTTP method overrides.
14 | * Such methods must match the spelling of an HTTP method in lower case (e.g, "get").
15 | * If a request has a matching method, it will be called as in
16 | * `get(info: requestInfo, db: {})` where `db` is the database object described above.
17 | */
18 | export declare abstract class InMemoryDbService {
19 | /**
20 | * Creates an in-memory "database" hash whose keys are collection names
21 | * and whose values are arrays of collection objects to return or update.
22 | *
23 | * returns Observable of the database because could have to create it asynchronously.
24 | *
25 | * This method must be safe to call repeatedly.
26 | * Each time it should return a new object with new arrays containing new item objects.
27 | * This condition allows the in-memory backend service to mutate the collections
28 | * and their items without touching the original source data.
29 | *
30 | * The in-mem backend service calls this method without a value the first time.
31 | * The service calls it with the `RequestInfo` when it receives a POST `commands/resetDb` request.
32 | * Your InMemoryDbService can adjust its behavior accordingly.
33 | */
34 | abstract createDb(reqInfo?: RequestInfo): {} | Observable<{}> | Promise<{}>;
35 | }
36 | /**
37 | * Interface for InMemoryBackend configuration options
38 | */
39 | export declare abstract class InMemoryBackendConfigArgs {
40 | /**
41 | * The base path to the api, e.g, 'api/'.
42 | * If not specified than `parseRequestUrl` assumes it is the first path segment in the request.
43 | */
44 | apiBase?: string;
45 | /**
46 | * false (default) if search match should be case insensitive
47 | */
48 | caseSensitiveSearch?: boolean;
49 | /**
50 | * false (default) put content directly inside the response body.
51 | * true: encapsulate content in a `data` property inside the response body, `{ data: ... }`.
52 | */
53 | dataEncapsulation?: boolean;
54 | /**
55 | * delay (in ms) to simulate latency
56 | */
57 | delay?: number;
58 | /**
59 | * false (default) should 204 when object-to-delete not found; true: 404
60 | */
61 | delete404?: boolean;
62 | /**
63 | * host for this service, e.g., 'localhost'
64 | */
65 | host?: string;
66 | /**
67 | * false (default) should pass unrecognized request URL through to original backend; true: 404
68 | */
69 | passThruUnknownUrl?: boolean;
70 | /**
71 | * true (default) should NOT return the item (204) after a POST. false: return the item (200).
72 | */
73 | post204?: boolean;
74 | /**
75 | * false (default) should NOT update existing item with POST. false: OK to update.
76 | */
77 | post409?: boolean;
78 | /**
79 | * true (default) should NOT return the item (204) after a POST. false: return the item (200).
80 | */
81 | put204?: boolean;
82 | /**
83 | * false (default) if item not found, create as new item; false: should 404.
84 | */
85 | put404?: boolean;
86 | /**
87 | * root path _before_ any API call, e.g., ''
88 | */
89 | rootPath?: string;
90 | }
91 | /**
92 | * InMemoryBackendService configuration options
93 | * Usage:
94 | * InMemoryWebApiModule.forRoot(InMemHeroService, {delay: 600})
95 | *
96 | * or if providing separately:
97 | * provide(InMemoryBackendConfig, {useValue: {delay: 600}}),
98 | */
99 | export declare class InMemoryBackendConfig implements InMemoryBackendConfigArgs {
100 | constructor(config?: InMemoryBackendConfigArgs);
101 | }
102 | /** Return information (UriInfo) about a URI */
103 | export declare function parseUri(str: string): UriInfo;
104 | /**
105 | *
106 | * Interface for the result of the `parseRequestUrl` method:
107 | * Given URL "http://localhost:8080/api/customers/42?foo=1 the default implementation returns
108 | * base: 'api/'
109 | * collectionName: 'customers'
110 | * id: '42'
111 | * query: this.createQuery('foo=1')
112 | * resourceUrl: 'http://localhost/api/customers/'
113 | */
114 | export interface ParsedRequestUrl {
115 | apiBase: string;
116 | collectionName: string;
117 | id: string;
118 | query: Map;
119 | resourceUrl: string;
120 | }
121 | export interface PassThruBackend {
122 | /**
123 | * Handle an HTTP request and return an Observable of HTTP response
124 | * Both the request type and the response type are determined by the supporting HTTP library.
125 | */
126 | handle(req: any): Observable;
127 | }
128 | export declare function removeTrailingSlash(path: string): string;
129 | /**
130 | * Minimum definition needed by base class
131 | */
132 | export interface RequestCore {
133 | url: string;
134 | urlWithParams?: string;
135 | }
136 | /**
137 | * Interface for object w/ info about the current request url
138 | * extracted from an Http Request.
139 | * Also holds utility methods and configuration data from this service
140 | */
141 | export interface RequestInfo {
142 | req: RequestCore;
143 | apiBase: string;
144 | collectionName: string;
145 | collection: any;
146 | headers: HeadersCore;
147 | method: string;
148 | id: any;
149 | query: Map;
150 | resourceUrl: string;
151 | url: string;
152 | utils: RequestInfoUtilities;
153 | }
154 | /**
155 | * Interface for utility methods from this service instance.
156 | * Useful within an HTTP method override
157 | */
158 | export interface RequestInfoUtilities {
159 | /**
160 | * Create a cold response Observable from a factory for ResponseOptions
161 | * the same way that the in-mem backend service does.
162 | * @param resOptionsFactory - creates ResponseOptions when observable is subscribed
163 | * @param withDelay - if true (default), add simulated latency delay from configuration
164 | */
165 | createResponse$: (resOptionsFactory: () => ResponseOptions) => Observable;
166 | /**
167 | * Find first instance of item in collection by `item.id`
168 | * @param collection
169 | * @param id
170 | */
171 | findById(collection: T[], id: any): T;
174 | /** return the current, active configuration which is a blend of defaults and overrides */
175 | getConfig(): InMemoryBackendConfigArgs;
176 | /** Get the in-mem service's copy of the "database" */
177 | getDb(): {};
178 | /** Get JSON body from the request object */
179 | getJsonBody(req: any): any;
180 | /** Get location info from a url, even on server where `document` is not defined */
181 | getLocation(url: string): UriInfo;
182 | /** Get (or create) the "real" backend */
183 | getPassThruBackend(): PassThruBackend;
184 | /**
185 | * return true if can determine that the collection's `item.id` is a number
186 | * */
187 | isCollectionIdNumeric(collection: T[], collectionName: string): boolean;
190 | /**
191 | * Parses the request URL into a `ParsedRequestUrl` object.
192 | * Parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.
193 | */
194 | parseRequestUrl(url: string): ParsedRequestUrl;
195 | }
196 | /**
197 | * Provide a `responseInterceptor` method of this type in your `inMemDbService` to
198 | * morph the response options created in the `collectionHandler`.
199 | */
200 | export declare type ResponseInterceptor = (res: ResponseOptions, ri: RequestInfo) => ResponseOptions;
201 | export interface ResponseOptions {
202 | /**
203 | * String, Object, ArrayBuffer or Blob representing the body of the {@link Response}.
204 | */
205 | body?: string | Object | ArrayBuffer | Blob;
206 | /**
207 | * Response headers
208 | */
209 | headers?: HeadersCore;
210 | /**
211 | * Http {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html status code}
212 | * associated with the response.
213 | */
214 | status?: number;
215 | /**
216 | * Status text for the status code
217 | */
218 | statusText?: string;
219 | /**
220 | * request url
221 | */
222 | url?: string;
223 | }
224 | /** Interface of information about a Uri */
225 | export interface UriInfo {
226 | source: string;
227 | protocol: string;
228 | authority: string;
229 | userInfo: string;
230 | user: string;
231 | password: string;
232 | host: string;
233 | port: string;
234 | relative: string;
235 | path: string;
236 | directory: string;
237 | file: string;
238 | query: string;
239 | anchor: string;
240 | }
241 |
--------------------------------------------------------------------------------
/interfaces.js:
--------------------------------------------------------------------------------
1 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4 | 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;
5 | return c > 3 && r && Object.defineProperty(target, key, r), r;
6 | };
7 | var __metadata = (this && this.__metadata) || function (k, v) {
8 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9 | };
10 | import { Injectable } from '@angular/core';
11 | /**
12 | * Interface for a class that creates an in-memory database
13 | *
14 | * Its `createDb` method creates a hash of named collections that represents the database
15 | *
16 | * For maximum flexibility, the service may define HTTP method overrides.
17 | * Such methods must match the spelling of an HTTP method in lower case (e.g, "get").
18 | * If a request has a matching method, it will be called as in
19 | * `get(info: requestInfo, db: {})` where `db` is the database object described above.
20 | */
21 | var InMemoryDbService = /** @class */ (function () {
22 | function InMemoryDbService() {
23 | }
24 | return InMemoryDbService;
25 | }());
26 | export { InMemoryDbService };
27 | /**
28 | * Interface for InMemoryBackend configuration options
29 | */
30 | var InMemoryBackendConfigArgs = /** @class */ (function () {
31 | function InMemoryBackendConfigArgs() {
32 | }
33 | return InMemoryBackendConfigArgs;
34 | }());
35 | export { InMemoryBackendConfigArgs };
36 | /////////////////////////////////
37 | /**
38 | * InMemoryBackendService configuration options
39 | * Usage:
40 | * InMemoryWebApiModule.forRoot(InMemHeroService, {delay: 600})
41 | *
42 | * or if providing separately:
43 | * provide(InMemoryBackendConfig, {useValue: {delay: 600}}),
44 | */
45 | var InMemoryBackendConfig = /** @class */ (function () {
46 | function InMemoryBackendConfig(config) {
47 | if (config === void 0) { config = {}; }
48 | Object.assign(this, {
49 | // default config:
50 | caseSensitiveSearch: false,
51 | dataEncapsulation: false,
52 | delay: 500,
53 | delete404: false,
54 | passThruUnknownUrl: false,
55 | post204: true,
56 | post409: false,
57 | put204: true,
58 | put404: false,
59 | apiBase: undefined,
60 | host: undefined,
61 | rootPath: undefined // default value is actually set in InMemoryBackendService ctor
62 | }, config);
63 | }
64 | InMemoryBackendConfig = __decorate([
65 | Injectable(),
66 | __metadata("design:paramtypes", [InMemoryBackendConfigArgs])
67 | ], InMemoryBackendConfig);
68 | return InMemoryBackendConfig;
69 | }());
70 | export { InMemoryBackendConfig };
71 | /** Return information (UriInfo) about a URI */
72 | export function parseUri(str) {
73 | // Adapted from parseuri package - http://blog.stevenlevithan.com/archives/parseuri
74 | // tslint:disable-next-line:max-line-length
75 | var URL_REGEX = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
76 | var m = URL_REGEX.exec(str);
77 | var uri = {
78 | source: '',
79 | protocol: '',
80 | authority: '',
81 | userInfo: '',
82 | user: '',
83 | password: '',
84 | host: '',
85 | port: '',
86 | relative: '',
87 | path: '',
88 | directory: '',
89 | file: '',
90 | query: '',
91 | anchor: ''
92 | };
93 | var keys = Object.keys(uri);
94 | var i = keys.length;
95 | while (i--) {
96 | uri[keys[i]] = m[i] || '';
97 | }
98 | return uri;
99 | }
100 | export function removeTrailingSlash(path) {
101 | return path.replace(/\/$/, '');
102 | }
103 | //# sourceMappingURL=interfaces.js.map
--------------------------------------------------------------------------------
/interfaces.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["interfaces.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAU3C;;;;;;;;;EASE;AACF;IAAA;IAiBA,CAAC;IAAD,wBAAC;AAAD,CAAC,AAjBD,IAiBC;;AAED;;EAEE;AACF;IAAA;IAmDA,CAAC;IAAD,gCAAC;AAAD,CAAC,AAnDD,IAmDC;;AAED,iCAAiC;AACjC;;;;;;;EAOE;AAEF;IACE,+BAAY,MAAsC;QAAtC,uBAAA,EAAA,WAAsC;QAChD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YAClB,kBAAkB;YAClB,mBAAmB,EAAE,KAAK;YAC1B,iBAAiB,EAAE,KAAK;YACxB,KAAK,EAAE,GAAG;YACV,SAAS,EAAE,KAAK;YAChB,kBAAkB,EAAE,KAAK;YACzB,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,SAAS;YAClB,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,SAAS,CAAC,+DAA+D;SACpF,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAjBU,qBAAqB;QADjC,UAAU,EAAE;yCAES,yBAAyB;OADlC,qBAAqB,CAkBjC;IAAD,4BAAC;CAAA,AAlBD,IAkBC;SAlBY,qBAAqB;AAoBlC,gDAAgD;AAChD,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,mFAAmF;IACnF,2CAA2C;IAC3C,IAAM,SAAS,GAAG,kMAAkM,CAAC;IACrN,IAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAM,GAAG,GAAY;QACnB,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,EAAE;QACR,QAAQ,EAAE,EAAE;QACZ,IAAI,EAAE,EAAE;QACR,SAAS,EAAE,EAAE;QACb,IAAI,EAAE,EAAE;QACR,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;KACX,CAAC;IACF,IAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KAAE;IAC1C,OAAO,GAAG,CAAC;AACb,CAAC;AA4BD,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC","sourcesContent":["import { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\n/**\n * Minimum definition needed by base class\n */\nexport interface HeadersCore {\n set(name: string, value: string): void | any;\n}\n\n/**\n* Interface for a class that creates an in-memory database\n*\n* Its `createDb` method creates a hash of named collections that represents the database\n*\n* For maximum flexibility, the service may define HTTP method overrides.\n* Such methods must match the spelling of an HTTP method in lower case (e.g, \"get\").\n* If a request has a matching method, it will be called as in\n* `get(info: requestInfo, db: {})` where `db` is the database object described above.\n*/\nexport abstract class InMemoryDbService {\n /**\n * Creates an in-memory \"database\" hash whose keys are collection names\n * and whose values are arrays of collection objects to return or update.\n *\n * returns Observable of the database because could have to create it asynchronously.\n *\n * This method must be safe to call repeatedly.\n * Each time it should return a new object with new arrays containing new item objects.\n * This condition allows the in-memory backend service to mutate the collections\n * and their items without touching the original source data.\n *\n * The in-mem backend service calls this method without a value the first time.\n * The service calls it with the `RequestInfo` when it receives a POST `commands/resetDb` request.\n * Your InMemoryDbService can adjust its behavior accordingly.\n */\n abstract createDb(reqInfo?: RequestInfo): {} | Observable<{}> | Promise<{}>;\n}\n\n/**\n* Interface for InMemoryBackend configuration options\n*/\nexport abstract class InMemoryBackendConfigArgs {\n /**\n * The base path to the api, e.g, 'api/'.\n * If not specified than `parseRequestUrl` assumes it is the first path segment in the request.\n */\n apiBase?: string;\n /**\n * false (default) if search match should be case insensitive\n */\n caseSensitiveSearch?: boolean;\n /**\n * false (default) put content directly inside the response body.\n * true: encapsulate content in a `data` property inside the response body, `{ data: ... }`.\n */\n dataEncapsulation?: boolean;\n /**\n * delay (in ms) to simulate latency\n */\n delay?: number;\n /**\n * false (default) should 204 when object-to-delete not found; true: 404\n */\n delete404?: boolean;\n /**\n * host for this service, e.g., 'localhost'\n */\n host?: string;\n /**\n * false (default) should pass unrecognized request URL through to original backend; true: 404\n */\n passThruUnknownUrl?: boolean;\n /**\n * true (default) should NOT return the item (204) after a POST. false: return the item (200).\n */\n post204?: boolean;\n /**\n * false (default) should NOT update existing item with POST. false: OK to update.\n */\n post409?: boolean;\n /**\n * true (default) should NOT return the item (204) after a POST. false: return the item (200).\n */\n put204?: boolean;\n /**\n * false (default) if item not found, create as new item; false: should 404.\n */\n put404?: boolean;\n /**\n * root path _before_ any API call, e.g., ''\n */\n rootPath?: string;\n}\n\n/////////////////////////////////\n/**\n* InMemoryBackendService configuration options\n* Usage:\n* InMemoryWebApiModule.forRoot(InMemHeroService, {delay: 600})\n*\n* or if providing separately:\n* provide(InMemoryBackendConfig, {useValue: {delay: 600}}),\n*/\n@Injectable()\nexport class InMemoryBackendConfig implements InMemoryBackendConfigArgs {\n constructor(config: InMemoryBackendConfigArgs = {}) {\n Object.assign(this, {\n // default config:\n caseSensitiveSearch: false,\n dataEncapsulation: false, // do NOT wrap content within an object with a `data` property\n delay: 500, // simulate latency by delaying response\n delete404: false, // don't complain if can't find entity to delete\n passThruUnknownUrl: false, // 404 if can't process URL\n post204: true, // don't return the item after a POST\n post409: false, // don't update existing item with that ID\n put204: true, // don't return the item after a PUT\n put404: false, // create new item if PUT item with that ID not found\n apiBase: undefined, // assumed to be the first path segment\n host: undefined, // default value is actually set in InMemoryBackendService ctor\n rootPath: undefined // default value is actually set in InMemoryBackendService ctor\n }, config);\n }\n}\n\n/** Return information (UriInfo) about a URI */\nexport function parseUri(str: string): UriInfo {\n // Adapted from parseuri package - http://blog.stevenlevithan.com/archives/parseuri\n // tslint:disable-next-line:max-line-length\n const URL_REGEX = /^(?:(?![^:@]+:[^:@\\/]*@)([^:\\/?#.]+):)?(?:\\/\\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\\/?#]*)(?::(\\d*))?)(((\\/(?:[^?#](?![^?#\\/]*\\.[^?#\\/.]+(?:[?#]|$)))*\\/?)?([^?#\\/]*))(?:\\?([^#]*))?(?:#(.*))?)/;\n const m = URL_REGEX.exec(str);\n const uri: UriInfo = {\n source: '',\n protocol: '',\n authority: '',\n userInfo: '',\n user: '',\n password: '',\n host: '',\n port: '',\n relative: '',\n path: '',\n directory: '',\n file: '',\n query: '',\n anchor: ''\n };\n const keys = Object.keys(uri);\n let i = keys.length;\n\n while (i--) { uri[keys[i]] = m[i] || ''; }\n return uri;\n}\n\n/**\n *\n * Interface for the result of the `parseRequestUrl` method:\n * Given URL \"http://localhost:8080/api/customers/42?foo=1 the default implementation returns\n * base: 'api/'\n * collectionName: 'customers'\n * id: '42'\n * query: this.createQuery('foo=1')\n * resourceUrl: 'http://localhost/api/customers/'\n */\nexport interface ParsedRequestUrl {\n apiBase: string; // the slash-terminated \"base\" for api requests (e.g. `api/`)\n collectionName: string; // the name of the collection of data items (e.g.,`customers`)\n id: string; // the (optional) id of the item in the collection (e.g., `42`)\n query: Map; // the query parameters;\n resourceUrl: string; // the effective URL for the resource (e.g., 'http://localhost/api/customers/')\n}\n\nexport interface PassThruBackend {\n /**\n * Handle an HTTP request and return an Observable of HTTP response\n * Both the request type and the response type are determined by the supporting HTTP library.\n */\n handle(req: any): Observable;\n}\n\nexport function removeTrailingSlash(path: string) {\n return path.replace(/\\/$/, '');\n}\n\n/**\n * Minimum definition needed by base class\n */\nexport interface RequestCore {\n url: string; // request URL\n urlWithParams?: string; // request URL with query parameters added by `HttpParams`\n}\n\n/**\n* Interface for object w/ info about the current request url\n* extracted from an Http Request.\n* Also holds utility methods and configuration data from this service\n*/\nexport interface RequestInfo {\n req: RequestCore; // concrete type depends upon the Http library\n apiBase: string;\n collectionName: string;\n collection: any;\n headers: HeadersCore;\n method: string;\n id: any;\n query: Map;\n resourceUrl: string;\n url: string; // request URL\n utils: RequestInfoUtilities;\n}\n\n/**\n * Interface for utility methods from this service instance.\n * Useful within an HTTP method override\n */\nexport interface RequestInfoUtilities {\n /**\n * Create a cold response Observable from a factory for ResponseOptions\n * the same way that the in-mem backend service does.\n * @param resOptionsFactory - creates ResponseOptions when observable is subscribed\n * @param withDelay - if true (default), add simulated latency delay from configuration\n */\n createResponse$: (resOptionsFactory: () => ResponseOptions) => Observable;\n\n /**\n * Find first instance of item in collection by `item.id`\n * @param collection\n * @param id\n */\n findById(collection: T[], id: any): T;\n\n /** return the current, active configuration which is a blend of defaults and overrides */\n getConfig(): InMemoryBackendConfigArgs;\n\n /** Get the in-mem service's copy of the \"database\" */\n getDb(): {};\n\n /** Get JSON body from the request object */\n getJsonBody(req: any): any;\n\n /** Get location info from a url, even on server where `document` is not defined */\n getLocation(url: string): UriInfo;\n\n /** Get (or create) the \"real\" backend */\n getPassThruBackend(): PassThruBackend;\n\n /**\n * return true if can determine that the collection's `item.id` is a number\n * */\n isCollectionIdNumeric(collection: T[], collectionName: string): boolean;\n\n /**\n * Parses the request URL into a `ParsedRequestUrl` object.\n * Parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.\n */\n parseRequestUrl(url: string): ParsedRequestUrl;\n}\n\n/**\n * Provide a `responseInterceptor` method of this type in your `inMemDbService` to\n * morph the response options created in the `collectionHandler`.\n */\nexport type ResponseInterceptor = (res: ResponseOptions, ri: RequestInfo) => ResponseOptions;\n\nexport interface ResponseOptions {\n /**\n * String, Object, ArrayBuffer or Blob representing the body of the {@link Response}.\n */\n body?: string | Object | ArrayBuffer | Blob;\n\n /**\n * Response headers\n */\n headers?: HeadersCore;\n\n /**\n * Http {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html status code}\n * associated with the response.\n */\n status?: number;\n\n /**\n * Status text for the status code\n */\n statusText?: string;\n /**\n * request url\n */\n url?: string;\n}\n\n/** Interface of information about a Uri */\nexport interface UriInfo {\n source: string;\n protocol: string;\n authority: string;\n userInfo: string;\n user: string;\n password: string;\n host: string;\n port: string;\n relative: string;\n path: string;\n directory: string;\n file: string;\n query: string;\n anchor: string;\n}\n"]}
--------------------------------------------------------------------------------
/interfaces.metadata.json:
--------------------------------------------------------------------------------
1 | [{"__symbolic":"module","version":4,"metadata":{"HeadersCore":{"__symbolic":"interface"},"InMemoryDbService":{"__symbolic":"class","members":{"createDb":[{"__symbolic":"method"}]}},"InMemoryBackendConfigArgs":{"__symbolic":"class"},"InMemoryBackendConfig":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Injectable","line":104,"character":1}}],"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","name":"InMemoryBackendConfigArgs"}]}]}},"parseUri":{"__symbolic":"function"},"ParsedRequestUrl":{"__symbolic":"interface"},"PassThruBackend":{"__symbolic":"interface"},"removeTrailingSlash":{"__symbolic":"function","parameters":["path"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbolic":"reference","name":"path"},"member":"replace"},"arguments":[{"__symbolic":"error","message":"Expression form not supported","line":181,"character":22},""]}},"RequestCore":{"__symbolic":"interface"},"RequestInfo":{"__symbolic":"interface"},"RequestInfoUtilities":{"__symbolic":"interface"},"ResponseInterceptor":{"__symbolic":"interface"},"ResponseOptions":{"__symbolic":"interface"},"UriInfo":{"__symbolic":"interface"}}}]
--------------------------------------------------------------------------------
/karma-test-shim.js:
--------------------------------------------------------------------------------
1 | // /*global jasmine, __karma__, window*/
2 | Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
3 |
4 | // Uncomment to get full stacktrace output. Sometimes helpful, usually not.
5 | // Error.stackTraceLimit = Infinity; //
6 |
7 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
8 |
9 | // builtPaths: root paths for output ("built") files
10 | // get from karma.config.js, then prefix with '/src/' (default is 'app/')
11 | var builtPaths = (__karma__.config.builtPaths || ['src/'])
12 | .map(function(p) { return '/base/'+p;});
13 |
14 | __karma__.loaded = function () { };
15 |
16 | function isJsFile(path) {
17 | return path.slice(-3) == '.js';
18 | }
19 |
20 | function isSpecFile(path) {
21 | return /\.spec\.(.*\.)?js$/.test(path);
22 | }
23 |
24 | // Is a "built" file if is JavaScript file in one of the "built" folders
25 | function isBuiltFile(path) {
26 | return isJsFile(path) &&
27 | builtPaths.reduce(function(keep, bp) {
28 | return keep || (path.substr(0, bp.length) === bp);
29 | }, false);
30 | }
31 |
32 | var allSpecFiles = Object.keys(window.__karma__.files)
33 | .filter(isSpecFile)
34 | .filter(isBuiltFile);
35 |
36 | System.config({
37 | baseURL: 'base/src',
38 | // add packages for application folders other than `app/`
39 | packages: {
40 | // a testing folder
41 | 'testing': { main: 'index.js', defaultExtension: 'js' },
42 | // other app folders
43 | 'in-mem': { main: 'index.js', defaultExtension: 'js' }
44 | },
45 |
46 | // Assume npm: is set in `paths` in systemjs.config
47 | // Map the angular testing umd bundles
48 | map: {
49 | '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
50 | '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
51 | '@angular/common/http/testing': 'npm:@angular/common/bundles/common-http-testing.umd.js',
52 | '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
53 | '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
54 | '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
55 | '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
56 | '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js',
57 | },
58 | });
59 |
60 | System.import('systemjs.config.js')
61 | .then(initTestBed)
62 | .then(initTesting);
63 |
64 | function initTestBed(){
65 | return Promise.all([
66 | System.import('@angular/core/testing'),
67 | System.import('@angular/platform-browser-dynamic/testing')
68 | ])
69 |
70 | .then(function (providers) {
71 | var coreTesting = providers[0];
72 | var browserTesting = providers[1];
73 |
74 | coreTesting.TestBed.initTestEnvironment(
75 | browserTesting.BrowserDynamicTestingModule,
76 | browserTesting.platformBrowserDynamicTesting());
77 | })
78 | }
79 |
80 | // Import all spec files and start karma
81 | function initTesting () {
82 | return Promise.all(
83 | allSpecFiles.map(function (moduleName) {
84 | return System.import(moduleName);
85 | })
86 | )
87 | .then(__karma__.start, __karma__.error);
88 | }
89 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // #docregion
2 | module.exports = function(config) {
3 |
4 | var appBase = 'src/'; // transpiled app JS and map files
5 | var appAssets = '/base/app/'; // component assets fetched by Angular's compiler
6 |
7 | // Testing helpers (optional) are conventionally in a folder called `testing`
8 | var testingBase = 'src/testing/'; // transpiled test JS and map files
9 | var testingSrcBase = 'src/testing/'; // test source TS files
10 |
11 | config.set({
12 | basePath: '',
13 | frameworks: ['jasmine-ajax', 'jasmine'],
14 |
15 | plugins: [
16 | require('karma-jasmine-ajax'),
17 | require('karma-jasmine'),
18 | require('karma-chrome-launcher'),
19 | require('karma-jasmine-html-reporter')
20 | ],
21 |
22 | client: {
23 | builtPaths: [appBase, testingBase], // add more spec base paths as needed
24 | clearContext: false // leave Jasmine Spec Runner output visible in browser
25 | },
26 |
27 | customLaunchers: {
28 | // From the CLI. Not used here but interesting
29 | // chrome setup for travis CI using chromium
30 | Chrome_travis_ci: {
31 | base: 'Chrome',
32 | flags: ['--no-sandbox']
33 | }
34 | },
35 |
36 | files: [
37 | // System.js for module loading
38 | 'node_modules/systemjs/dist/system.src.js',
39 |
40 | // Polyfills
41 | 'node_modules/core-js/client/shim.js',
42 |
43 | // zone.js
44 | 'node_modules/zone.js/dist/zone.js',
45 | 'node_modules/zone.js/dist/long-stack-trace-zone.js',
46 | 'node_modules/zone.js/dist/proxy.js',
47 | 'node_modules/zone.js/dist/sync-test.js',
48 | 'node_modules/zone.js/dist/jasmine-patch.js',
49 | 'node_modules/zone.js/dist/async-test.js',
50 | 'node_modules/zone.js/dist/fake-async-test.js',
51 |
52 | // RxJs
53 | { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
54 | { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
55 |
56 | // tslib (TS helper fns such as `__extends`)
57 | { pattern: 'node_modules/tslib/**/*.js', included: false, watched: false },
58 | { pattern: 'node_modules/tslib/**/*.js.map', included: false, watched: false },
59 |
60 | // Paths loaded via module imports:
61 | // Angular itself
62 | { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false },
63 | { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false },
64 |
65 | { pattern: appBase + '/systemjs.config.js', included: false, watched: false },
66 |
67 | 'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels
68 |
69 | // transpiled application & spec code paths loaded via module imports
70 | { pattern: appBase + '**/*.js', included: false, watched: true },
71 | { pattern: testingBase + '**/*.js', included: false, watched: true },
72 |
73 |
74 | // Asset (HTML & CSS) paths loaded via Angular's component compiler
75 | // (these paths need to be rewritten, see proxies section)
76 | { pattern: appBase + '**/*.html', included: false, watched: true },
77 | { pattern: appBase + '**/*.css', included: false, watched: true },
78 |
79 | // Paths for debugging with source maps in dev tools
80 | { pattern: appBase + '**/*.ts', included: false, watched: false },
81 | { pattern: appBase + '**/*.js.map', included: false, watched: false },
82 | { pattern: testingSrcBase + '**/*.ts', included: false, watched: false },
83 | { pattern: testingBase + '**/*.js.map', included: false, watched: false}
84 | ],
85 |
86 | // Proxied base paths for loading assets
87 | proxies: {
88 | // required for modules fetched by SystemJS
89 | '/base/src/node_modules/': '/base/node_modules/'
90 | },
91 |
92 | exclude: [],
93 | preprocessors: {},
94 | reporters: ['progress', 'kjhtml'],
95 |
96 | port: 9876,
97 | colors: true,
98 | logLevel: config.LOG_INFO,
99 | autoWatch: true,
100 | browsers: ['Chrome'],
101 | singleRun: false
102 | })
103 | }
104 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-in-memory-web-api",
3 | "version": "0.10.0",
4 | "description": "An in-memory web api for Angular demos and tests",
5 | "main": "bundles/in-memory-web-api.umd.js",
6 | "module": "index.js",
7 | "scripts": {
8 | "build": "tsc",
9 | "build:watch": "tsc -w",
10 | "build:lib": "gulp build",
11 | "lint": "tslint ./src/*.ts -t verbose -e ./src/*.d.ts",
12 | "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
13 | "pretest": "npm run build",
14 | "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
15 | "pretest:once": "npm run build",
16 | "test:once": "karma start karma.conf.js --single-run",
17 | "tsc": "tsc",
18 | "tsc:w": "tsc -w"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/angular/in-memory-web-api.git"
23 | },
24 | "keywords": [],
25 | "author": "",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/angular/in-memory-web-api/issues"
29 | },
30 | "homepage": "https://github.com/angular/in-memory-web-api#readme",
31 | "peerDependencies": {
32 | "@angular/common": ">=8.0.0",
33 | "@angular/core": ">=8.0.0",
34 | "rxjs": "^6.0.0"
35 | },
36 | "devDependencies": {
37 | "@angular/animations": "^8.0.0",
38 | "@angular/common": "^8.0.0",
39 | "@angular/compiler": "^8.0.0",
40 | "@angular/compiler-cli": "^8.0.0",
41 | "@angular/core": "^8.0.0",
42 | "@angular/platform-browser": "^8.0.0",
43 | "@angular/platform-browser-dynamic": "^8.0.0",
44 | "@angular/platform-server": "^8.0.0",
45 | "@types/jasmine": "2.8.7",
46 | "@types/jasminewd2": "~2.0.3",
47 | "@types/jasmine-ajax": "^3.1.37",
48 | "@types/node": "^8.10.0",
49 | "canonical-path": "0.0.2",
50 | "concurrently": "^3.0.0",
51 | "core-js": "^2.4.1",
52 | "del": "^2.2.2",
53 | "gulp": "^4.0.2",
54 | "gulp-bump": "^3.1.3",
55 | "gulp-load-plugins": "^2.0.3",
56 | "gulp-task-listing": "^1.1.0",
57 | "http-server": "^0.9.0",
58 | "jasmine-ajax": "^3.3.1",
59 | "jasmine-core": "~2.8.0",
60 | "jasmine-spec-reporter": "~4.2.1",
61 | "karma": "~2.0.0",
62 | "karma-chrome-launcher": "~2.2.0",
63 | "karma-cli": "~1.0.1",
64 | "karma-coverage-istanbul-reporter": "~2.0.0",
65 | "karma-jasmine": "~1.1.1",
66 | "karma-jasmine-html-reporter": "^0.2.2",
67 | "karma-jasmine-ajax": "^0.1.13",
68 | "karma-phantomjs-launcher": "^1.0.4",
69 | "karma-sourcemap-loader": "^0.3.7",
70 | "karma-webpack": "^3.0.0",
71 | "lite-server": "^2.3.0",
72 | "lodash": "^4.17.10",
73 | "rimraf": "^2.6.2",
74 | "rollup": "^0.58.2",
75 | "rollup-stream": "^1.24.1",
76 | "rxjs": "^6.2.0",
77 | "systemjs": "0.21.3",
78 | "tslint": "^5.10.0",
79 | "typescript": "3.4.5",
80 | "vinyl-source-stream": "^2.0.0",
81 | "webpack": "2.2.1",
82 | "yargs": "^11.0.0",
83 | "zone.js": "^0.9.1"
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | const globals = {
2 | '@angular/core': 'ng.core',
3 | '@angular/common/http': 'ng.common.http',
4 | 'rxjs': 'rxjs',
5 | 'rxjs/operators': 'rxjs.operators'
6 | };
7 |
8 | export default {
9 | input: './src/in-mem/index.js',
10 | file: './bundles/in-memory-web-api.umd.js',
11 | format: 'umd',
12 | name: 'ng.inMemoryWebApi',
13 | sourcemap: true,
14 | globals,
15 | external: Object.keys(globals)
16 | }
17 |
--------------------------------------------------------------------------------
/src/app/hero-in-mem-data-override.service.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of a Hero-oriented InMemoryDbService with method overrides.
3 | */
4 | import { Injectable } from '@angular/core';
5 |
6 | // tslint:disable-next-line:no-unused-variable
7 | import { Observable } from 'rxjs';
8 |
9 | import { ParsedRequestUrl, RequestInfo, RequestInfoUtilities, ResponseOptions } from '../in-mem/interfaces';
10 |
11 | import { getStatusText, STATUS } from '../in-mem/http-status-codes';
12 |
13 | import { HeroInMemDataService } from './hero-in-mem-data.service';
14 |
15 | const villains = [
16 | // deliberately using string ids that look numeric
17 | {id: 100, name: 'Snidley Wipsnatch'},
18 | {id: 101, name: 'Boris Badenov'},
19 | {id: 103, name: 'Natasha Fatale'}
20 | ];
21 |
22 | // Pseudo guid generator
23 | function guid() {
24 | function s4() {
25 | return Math.floor((1 + Math.random()) * 0x10000)
26 | .toString(16)
27 | .substring(1);
28 | }
29 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
30 | s4() + '-' + s4() + s4() + s4();
31 | }
32 |
33 | @Injectable()
34 | export class HeroInMemDataOverrideService extends HeroInMemDataService {
35 |
36 | // Overrides id generator and delivers next available `id`, starting with 1001.
37 | genId(collection: T[], collectionName: string): any {
38 | if (collectionName === 'nobodies') {
39 | console.log('genId override for \'nobodies\'');
40 | return guid();
41 | } else if (collection) {
42 | console.log(`genId override for '${collectionName}'`);
43 | return 1 + collection.reduce((prev, curr) => Math.max(prev, curr.id || 0), 1000);
44 | }
45 | }
46 |
47 | // HTTP GET interceptor
48 | get(reqInfo: RequestInfo) {
49 | const collectionName = reqInfo.collectionName;
50 | if (collectionName === 'villains') {
51 | return this.getVillains(reqInfo);
52 | }
53 | return undefined; // let the default GET handle all others
54 | }
55 |
56 | // HTTP GET interceptor handles requests for villains
57 | private getVillains(reqInfo: RequestInfo) {
58 | return reqInfo.utils.createResponse$(() => {
59 | console.log('HTTP GET override');
60 |
61 | const collection = villains.slice();
62 | const dataEncapsulation = reqInfo.utils.getConfig().dataEncapsulation;
63 | const id = reqInfo.id;
64 |
65 | // tslint:disable-next-line:triple-equals
66 | const data = id == undefined ? collection : reqInfo.utils.findById(collection, id);
67 |
68 | const options: ResponseOptions = data ?
69 | {
70 | body: dataEncapsulation ? { data } : data,
71 | status: STATUS.OK
72 | } :
73 | {
74 | body: { error: `'Villains' with id='${id}' not found` },
75 | status: STATUS.NOT_FOUND
76 | };
77 | return this.finishOptions(options, reqInfo);
78 | });
79 | }
80 |
81 | // parseRequestUrl override
82 | // Do this to manipulate the request URL or the parsed result
83 | // into something your data store can handle.
84 | // This example turns a request for `/foo/heroes` into just `/heroes`.
85 | // It leaves other URLs untouched and forwards to the default parser.
86 | // It also logs the result of the default parser.
87 | parseRequestUrl(url: string, utils: RequestInfoUtilities): ParsedRequestUrl {
88 | const newUrl = url.replace(/\/foo\/heroes/, '/heroes');
89 | // console.log('newUrl', newUrl);
90 | const parsed = utils.parseRequestUrl(newUrl);
91 | console.log(`parseRequestUrl override of '${url}':`, parsed);
92 | return parsed;
93 | }
94 |
95 | // intercept ResponseOptions from default HTTP method handlers
96 | // add a response header and report interception to console.log
97 | responseInterceptor(resOptions: ResponseOptions, reqInfo: RequestInfo) {
98 |
99 | resOptions.headers = resOptions.headers.set('x-test', 'test-header');
100 | const method = reqInfo.method.toUpperCase();
101 | const body = JSON.stringify(resOptions);
102 | console.log(`responseInterceptor: ${method} ${reqInfo.req.url}: \n${body}`);
103 |
104 | return resOptions;
105 | }
106 |
107 | /////////// helpers ///////////////
108 |
109 | private finishOptions(options: ResponseOptions, {headers, url}: RequestInfo) {
110 | options.statusText = getStatusText(options.status);
111 | options.headers = headers;
112 | options.url = url;
113 | return options;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/app/hero-in-mem-data.service.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This is an example of a Hero-oriented InMemoryDbService.
3 | *
4 | * For demonstration purposes, it can return the database
5 | * synchronously as an object (default),
6 | * as an observable, or as a promise.
7 | *
8 | * Add the following line to `AppModule.imports`
9 | * InMemoryWebApiModule.forRoot(HeroInMemDataService) // or HeroInMemDataOverrideService
10 | */
11 | import { Injectable } from '@angular/core';
12 | import { InMemoryDbService, RequestInfo } from '../in-mem/interfaces';
13 |
14 | // tslint:disable:no-unused-variable
15 | import { Observable, of } from 'rxjs';
16 | import { delay } from 'rxjs/operators';
17 | // tslint:enable:no-unused-variable
18 |
19 | @Injectable()
20 | export class HeroInMemDataService implements InMemoryDbService {
21 | createDb(reqInfo?: RequestInfo) {
22 |
23 | const heroes = [
24 | { id: 1, name: 'Windstorm' },
25 | { id: 2, name: 'Bombasto' },
26 | { id: 3, name: 'Magneta' },
27 | { id: 4, name: 'Tornado' }
28 | ];
29 |
30 | const nobodies: any[] = [ ];
31 |
32 | // entities with string ids that look like numbers
33 | const stringers = [
34 | { id: '10', name: 'Bob String'},
35 | { id: '20', name: 'Jill String'}
36 | ];
37 |
38 | // default returnType
39 | let returnType = 'object';
40 | // let returnType = 'observable';
41 | // let returnType = 'promise';
42 |
43 | // demonstrate POST commands/resetDb
44 | // this example clears the collections if the request body tells it to do so
45 | if (reqInfo) {
46 | const body = reqInfo.utils.getJsonBody(reqInfo.req) || {};
47 | if (body.clear === true) {
48 | heroes.length = 0;
49 | nobodies.length = 0;
50 | stringers.length = 0;
51 | }
52 |
53 | // 'returnType` can be 'object' | 'observable' | 'promise'
54 | returnType = body.returnType || 'object';
55 | }
56 | const db = { heroes, nobodies, stringers };
57 |
58 | switch (returnType) {
59 | case ('observable'):
60 | return of(db).pipe(delay(10));
61 | case ('promise'):
62 | return new Promise(resolve => {
63 | setTimeout(() => resolve(db), 10);
64 | });
65 | default:
66 | return db;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/app/hero.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, TestBed } from '@angular/core/testing';
2 |
3 | import { concatMap, tap, map } from 'rxjs/operators';
4 |
5 | import { failure } from '../testing';
6 |
7 | import { Hero } from './hero';
8 | import { HeroService } from './hero.service';
9 |
10 | /**
11 | * Common tests for the HeroService, whether implemented with Http or HttpClient
12 | * Assumes that TestBed has been configured appropriately before created and run.
13 | *
14 | * Tests with extended test expirations accommodate the default (simulated) latency delay.
15 | * Ideally configured for short or no delay.
16 | */
17 | export class HeroServiceCoreSpec {
18 |
19 | run() {
20 |
21 | describe('HeroService core', () => {
22 |
23 | let heroService: HeroService;
24 |
25 | beforeEach(function() {
26 | heroService = TestBed.get(HeroService);
27 | });
28 |
29 | it('can get heroes', async(() => {
30 | heroService.getHeroes()
31 | .subscribe(
32 | heroes => {
33 | // console.log(heroes);
34 | expect(heroes.length).toBeGreaterThan(0, 'should have heroes');
35 | },
36 | failure
37 | );
38 | }));
39 |
40 | it('can get hero w/ id=1', async(() => {
41 | heroService.getHero(1)
42 | .subscribe(
43 | hero => {
44 | // console.log(hero);
45 | expect(hero.name).toBe('Windstorm');
46 | },
47 | () => fail('getHero failed')
48 | );
49 | }));
50 |
51 | it('should 404 when hero id not found', async(() => {
52 | const id = 123456;
53 | heroService.getHero(id)
54 | .subscribe(
55 | () => fail(`should not have found hero for id='${id}'`),
56 | err => {
57 | expect(err.status).toBe(404, 'should have 404 status');
58 | }
59 | );
60 | }));
61 |
62 | it('can add a hero', async(() => {
63 | heroService.addHero('FunkyBob').pipe(
64 | tap(hero => {
65 | // console.log(hero);
66 | expect(hero.name).toBe('FunkyBob');
67 | }),
68 | // Get the new hero by its generated id
69 | concatMap(hero => heroService.getHero(hero.id)),
70 | ).subscribe(
71 | hero => {
72 | expect(hero.name).toBe('FunkyBob');
73 | },
74 | err => failure('re-fetch of new hero failed')
75 | );
76 | }), 10000);
77 |
78 | it('can delete a hero', async(() => {
79 | const id = 1;
80 | heroService.deleteHero(id)
81 | .subscribe(
82 | (_: {}) => {
83 | expect(_).toBeDefined();
84 | },
85 | failure
86 | );
87 | }));
88 |
89 | it('should allow delete of non-existent hero', async(() => {
90 | const id = 123456;
91 | heroService.deleteHero(id)
92 | .subscribe(
93 | (_: {}) => {
94 | expect(_).toBeDefined();
95 | },
96 | failure
97 | );
98 | }));
99 |
100 | it('can search for heroes by name containing "a"', async(() => {
101 | heroService.searchHeroes('a')
102 | .subscribe(
103 | (heroes: Hero[]) => {
104 | expect(heroes.length).toBe(3, 'should find 3 heroes with letter "a"');
105 | },
106 | failure
107 | );
108 | }));
109 |
110 | it('can update existing hero', async(() => {
111 | const id = 1;
112 | heroService.getHero(id).pipe(
113 | concatMap(hero => {
114 | hero.name = 'Thunderstorm';
115 | return heroService.updateHero(hero);
116 | }),
117 | concatMap(() => {
118 | return heroService.getHero(id);
119 | })
120 | ).subscribe(
121 | hero => {
122 | console.log(hero);
123 | expect(hero.name).toBe('Thunderstorm');
124 | },
125 | err => fail('re-fetch of updated hero failed')
126 | );
127 | }), 10000);
128 |
129 | it('should create new hero when try to update non-existent hero', async(() => {
130 | const falseHero = new Hero(12321, 'DryMan');
131 |
132 | heroService.updateHero(falseHero)
133 | .subscribe(
134 | hero => {
135 | expect(hero.name).toBe(falseHero.name);
136 | },
137 | failure
138 | );
139 | }));
140 |
141 | });
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/app/hero.service.ts:
--------------------------------------------------------------------------------
1 | import { Hero } from './hero';
2 | import { Observable } from 'rxjs';
3 |
4 | export abstract class HeroService {
5 | heroesUrl = 'api/heroes'; // URL to web api
6 |
7 | abstract getHeroes (): Observable;
8 | abstract getHero(id: number): Observable;
9 | abstract addHero (name: string): Observable;
10 | abstract deleteHero (hero: Hero | number): Observable;
11 | abstract searchHeroes(term: string): Observable;
12 | abstract updateHero (hero: Hero): Observable;
13 | }
14 |
--------------------------------------------------------------------------------
/src/app/hero.ts:
--------------------------------------------------------------------------------
1 | export class Hero {
2 | constructor(public id = 0, public name = '') { }
3 | clone() { return new Hero(this.id, this.name); }
4 | }
5 |
--------------------------------------------------------------------------------
/src/app/http-client-hero.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable }from '@angular/core';
2 | import { HttpClient, HttpHeaders, HttpParams }from '@angular/common/http';
3 |
4 | import { Observable, throwError } from 'rxjs';
5 | import { tap, catchError, map } from 'rxjs/operators';
6 |
7 | import { Hero } from './hero';
8 | import { HeroService } from './hero.service';
9 |
10 | const cudOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' })};
11 |
12 | @Injectable()
13 | export class HttpClientHeroService extends HeroService {
14 |
15 | constructor (private http: HttpClient) {
16 | super();
17 | }
18 |
19 | getHeroes (): Observable {
20 | return this.http.get(this.heroesUrl).pipe(
21 | // tap(data => console.log(data)), // eyeball results in the console
22 | catchError(this.handleError)
23 | );
24 | }
25 |
26 | // This get-by-id will 404 when id not found
27 | getHero(id: number): Observable {
28 | const url = `${this.heroesUrl}/${id}`;
29 | return this.http.get(url).pipe(
30 | catchError(this.handleError)
31 | );
32 | }
33 |
34 | // This get-by-id does not 404; returns undefined when id not found
35 | // getHero(id: number): Observable {
36 | // const url = `${this._heroesUrl}/?id=${id}`;
37 | // return this.http.get(url)
38 | // .map(heroes => heroes[0] as Hero)
39 | // .catch(this.handleError);
40 | // }
41 |
42 | addHero (name: string): Observable {
43 | const hero = { name };
44 |
45 | return this.http.post(this.heroesUrl, hero, cudOptions).pipe(
46 | catchError(this.handleError)
47 | );
48 | }
49 |
50 | deleteHero (hero: Hero | number): Observable {
51 | const id = typeof hero === 'number' ? hero : hero.id;
52 | const url = `${this.heroesUrl}/${id}`;
53 |
54 | return this.http.delete(url, cudOptions).pipe(
55 | catchError(this.handleError)
56 | );
57 | }
58 |
59 | searchHeroes(term: string): Observable {
60 | term = term.trim();
61 | // add safe, encoded search parameter if term is present
62 | const options = term ?
63 | { params: new HttpParams().set('name', term) } : {};
64 |
65 | return this.http.get(this.heroesUrl, options).pipe(
66 | catchError(this.handleError)
67 | );
68 | }
69 |
70 | updateHero (hero: Hero): Observable {
71 | return this.http.put(this.heroesUrl, hero, cudOptions).pipe(
72 | catchError(this.handleError)
73 | );
74 | }
75 |
76 | private handleError (error: any) {
77 | // In a real world app, we might send the error to remote logging infrastructure
78 | // and reformat for user consumption
79 | console.error(error); // log to console instead
80 | return throwError(error);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/in-mem/backend.service.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbol":1,"members":[]},{"__symbol":2,"members":[]}]}],"handleRequest":[{"__symbolic":"method"}],"handleRequest_":[{"__symbolic":"method"}],"addDelay":[{"__symbolic":"method"}],"applyQuery":[{"__symbolic":"method"}],"bind":[{"__symbolic":"method"}],"bodify":[{"__symbolic":"method"}],"clone":[{"__symbolic":"method"}],"collectionHandler":[{"__symbolic":"method"}],"commands":[{"__symbolic":"method"}],"createErrorResponseOptions":[{"__symbolic":"method"}],"createHeaders":[{"__symbolic":"method"}],"createPassThruBackend":[{"__symbolic":"method"}],"createQueryMap":[{"__symbolic":"method"}],"createResponse$":[{"__symbolic":"method"}],"createResponse$fromResponseOptions$":[{"__symbolic":"method"}],"createResponseOptions$":[{"__symbolic":"method"}],"delete":[{"__symbolic":"method"}],"findById":[{"__symbolic":"method"}],"genId":[{"__symbolic":"method"}],"genIdDefault":[{"__symbolic":"method"}],"get":[{"__symbolic":"method"}],"getJsonBody":[{"__symbolic":"method"}],"getLocation":[{"__symbolic":"method"}],"getPassThruBackend":[{"__symbolic":"method"}],"getRequestInfoUtils":[{"__symbolic":"method"}],"getRequestMethod":[{"__symbolic":"method"}],"indexOf":[{"__symbolic":"method"}],"parseId":[{"__symbolic":"method"}],"isCollectionIdNumeric":[{"__symbolic":"method"}],"parseRequestUrl":[{"__symbolic":"method"}],"post":[{"__symbolic":"method"}],"put":[{"__symbolic":"method"}],"removeById":[{"__symbolic":"method"}],"resetDb":[{"__symbolic":"method"}]}}}],"symbols":[{"__symbol":0,"name":"BackendService","filePath":"./backend.service"},{"__symbol":1,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":2,"name":"InMemoryBackendConfigArgs","filePath":"./interfaces"}]}
--------------------------------------------------------------------------------
/src/in-mem/delay-response.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"function","parameters":["response$","delayMs"],"value":{"__symbolic":"new","expression":{"__symbol":1,"members":[]},"arguments":[{"__symbolic":"error","message":"Lambda not supported","fileName":"src\\in-mem\\delay-response.ts"}]}}}],"symbols":[{"__symbol":0,"name":"delayResponse","filePath":"./delay-response"},{"__symbol":1,"name":"Observable","filePath":"rxjs"}]}
--------------------------------------------------------------------------------
/src/in-mem/delay-response.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 |
3 | // Replaces use of RxJS delay. See v0.5.4.
4 | /** adds specified delay (in ms) to both next and error channels of the response observable */
5 | export function delayResponse(response$: Observable, delayMs: number): Observable {
6 | return new Observable(observer => {
7 | let completePending = false;
8 | let nextPending = false;
9 | const subscription = response$.subscribe(
10 | value => {
11 | nextPending = true;
12 | setTimeout(() => {
13 | observer.next(value);
14 | if (completePending) {
15 | observer.complete();
16 | }
17 | }, delayMs);
18 | },
19 | error => setTimeout(() => observer.error(error), delayMs),
20 | () => {
21 | completePending = true;
22 | if (!nextPending) {
23 | observer.complete();
24 | }
25 | }
26 | );
27 | return () => {
28 | return subscription.unsubscribe();
29 | };
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/src/in-mem/http-client-backend.service.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"class","extends":{"__symbol":1,"members":[]},"members":{"__ctor__":[{"__symbolic":"constructor","parameterDecorators":[null,[{"__symbolic":"call","expression":{"__symbol":2,"members":[]},"arguments":[{"__symbol":3,"members":[]}]},{"__symbolic":"call","expression":{"__symbol":4,"members":[]}}],null],"parameters":[{"__symbol":5,"members":[]},{"__symbol":6,"members":[]},{"__symbol":7,"members":[]}]}],"handle":[{"__symbolic":"method"}],"getJsonBody":[{"__symbolic":"method"}],"getRequestMethod":[{"__symbolic":"method"}],"createHeaders":[{"__symbolic":"method"}],"createQueryMap":[{"__symbolic":"method"}],"createResponse$fromResponseOptions$":[{"__symbolic":"method"}],"createPassThruBackend":[{"__symbolic":"method"}]}},"type":{"summaryKind":3,"type":{"reference":{"__symbol":0,"members":[]},"diDeps":[{"isAttribute":false,"isHost":false,"isSelf":false,"isSkipSelf":false,"isOptional":false,"token":{"identifier":{"reference":{"__symbol":5,"members":[]}}}},{"isAttribute":false,"isHost":false,"isSelf":false,"isSkipSelf":false,"isOptional":true,"token":{"identifier":{"reference":{"__symbol":3,"members":[]}}}},{"isAttribute":false,"isHost":false,"isSelf":false,"isSkipSelf":false,"isOptional":false,"token":{"identifier":{"reference":{"__symbol":7,"members":[]}}}}],"lifecycleHooks":[]}}}],"symbols":[{"__symbol":0,"name":"HttpClientBackendService","filePath":"./http-client-backend.service"},{"__symbol":1,"name":"BackendService","filePath":"./backend.service"},{"__symbol":2,"name":"Inject","filePath":"@angular/core"},{"__symbol":3,"name":"InMemoryBackendConfig","filePath":"./interfaces"},{"__symbol":4,"name":"Optional","filePath":"@angular/core"},{"__symbol":5,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":6,"name":"InMemoryBackendConfigArgs","filePath":"./interfaces"},{"__symbol":7,"name":"XhrFactory","filePath":"@angular/common/http/http"}]}
--------------------------------------------------------------------------------
/src/in-mem/http-client-backend.service.ts:
--------------------------------------------------------------------------------
1 | import { Inject, Injectable, Optional } from '@angular/core';
2 | import {
3 | HttpBackend,
4 | HttpEvent,
5 | HttpHeaders,
6 | HttpParams,
7 | HttpRequest,
8 | HttpResponse, HttpResponseBase,
9 | HttpXhrBackend,
10 | XhrFactory
11 | } from '@angular/common/http';
12 |
13 | import { Observable } from 'rxjs';
14 | import { map } from 'rxjs/operators';
15 |
16 | import { STATUS } from './http-status-codes';
17 |
18 | import {
19 | InMemoryBackendConfig,
20 | InMemoryBackendConfigArgs,
21 | InMemoryDbService,
22 | ResponseOptions
23 | } from './interfaces';
24 |
25 | import { BackendService } from './backend.service';
26 |
27 | /**
28 | * For Angular `HttpClient` simulate the behavior of a RESTy web api
29 | * backed by the simple in-memory data store provided by the injected `InMemoryDbService`.
30 | * Conforms mostly to behavior described here:
31 | * http://www.restapitutorial.com/lessons/httpmethods.html
32 | *
33 | * ### Usage
34 | *
35 | * Create an in-memory data store class that implements `InMemoryDbService`.
36 | * Call `config` static method with this service class and optional configuration object:
37 | * ```
38 | * // other imports
39 | * import { HttpClientModule } from '@angular/common/http';
40 | * import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
41 | *
42 | * import { InMemHeroService, inMemConfig } from '../api/in-memory-hero.service';
43 | * @NgModule({
44 | * imports: [
45 | * HttpModule,
46 | * HttpClientInMemoryWebApiModule.forRoot(InMemHeroService, inMemConfig),
47 | * ...
48 | * ],
49 | * ...
50 | * })
51 | * export class AppModule { ... }
52 | * ```
53 | */
54 | @Injectable()
55 | export class HttpClientBackendService extends BackendService implements HttpBackend {
56 |
57 | constructor(
58 | inMemDbService: InMemoryDbService,
59 | @Inject(InMemoryBackendConfig) @Optional() config: InMemoryBackendConfigArgs,
60 | private xhrFactory: XhrFactory
61 | ) {
62 | super(inMemDbService, config);
63 | }
64 |
65 | handle(req: HttpRequest): Observable> {
66 | try {
67 | return this.handleRequest(req);
68 |
69 | } catch (error) {
70 | const err = error.message || error;
71 | const resOptions = this.createErrorResponseOptions(req.url, STATUS.INTERNAL_SERVER_ERROR, `${err}`);
72 | return this.createResponse$(() => resOptions);
73 | }
74 | }
75 |
76 | //// protected overrides /////
77 |
78 | protected getJsonBody(req: HttpRequest): any {
79 | return req.body;
80 | }
81 |
82 | protected getRequestMethod(req: HttpRequest): string {
83 | return (req.method || 'get').toLowerCase();
84 | }
85 |
86 | protected createHeaders(headers: { [index: string]: string; }): HttpHeaders {
87 | return new HttpHeaders(headers);
88 | }
89 |
90 | protected createQueryMap(search: string): Map {
91 | const map = new Map();
92 | if (search) {
93 | const params = new HttpParams({fromString: search});
94 | params.keys().forEach(p => map.set(p, params.getAll(p)));
95 | }
96 | return map;
97 | }
98 |
99 | protected createResponse$fromResponseOptions$(resOptions$: Observable): Observable> {
100 | return resOptions$.pipe(map((opts: HttpResponseBase) => new HttpResponse(opts)));
101 | }
102 |
103 | protected createPassThruBackend() {
104 | try {
105 | return new HttpXhrBackend(this.xhrFactory);
106 | } catch (ex) {
107 | ex.message = 'Cannot create passThru404 backend; ' + (ex.message || '');
108 | throw ex;
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/in-mem/http-client-in-memory-web-api.module.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"function"}},{"symbol":{"__symbol":1,"members":[]},"metadata":{"__symbolic":"class","statics":{"forRoot":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"ngModule":{"__symbol":1,"members":[]},"providers":[{"provide":{"__symbol":2,"members":[]},"useClass":{"__symbolic":"reference","name":"dbCreator"}},{"provide":{"__symbol":3,"members":[]},"useValue":{"__symbolic":"reference","name":"options"}},{"provide":{"__symbol":4,"members":[]},"useFactory":{"__symbol":0,"members":[]},"deps":[{"__symbol":2,"members":[]},{"__symbol":3,"members":[]},{"__symbol":5,"members":[]}]}]}},"forFeature":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbol":1,"members":[]},"member":"forRoot"},"arguments":[{"__symbolic":"reference","name":"dbCreator"},{"__symbolic":"reference","name":"options"}]}}}},"type":{"summaryKind":2,"type":{"reference":{"__symbol":1,"members":[]},"diDeps":[],"lifecycleHooks":[]},"entryComponents":[],"providers":[],"modules":[{"reference":{"__symbol":1,"members":[]},"diDeps":[],"lifecycleHooks":[]}],"exportedDirectives":[],"exportedPipes":[]}}],"symbols":[{"__symbol":0,"name":"httpClientInMemBackendServiceFactory","filePath":"./http-client-in-memory-web-api.module"},{"__symbol":1,"name":"HttpClientInMemoryWebApiModule","filePath":"./http-client-in-memory-web-api.module"},{"__symbol":2,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":3,"name":"InMemoryBackendConfig","filePath":"./interfaces"},{"__symbol":4,"name":"HttpBackend","filePath":"@angular/common/http/http"},{"__symbol":5,"name":"XhrFactory","filePath":"@angular/common/http/http"}]}
--------------------------------------------------------------------------------
/src/in-mem/http-client-in-memory-web-api.module.ts:
--------------------------------------------------------------------------------
1 | ////// HttpClient-Only version ////
2 |
3 | import { NgModule, ModuleWithProviders, Type } from '@angular/core';
4 | import { HttpBackend, XhrFactory } from '@angular/common/http';
5 |
6 | import {
7 | InMemoryBackendConfigArgs,
8 | InMemoryBackendConfig,
9 | InMemoryDbService
10 | } from './interfaces';
11 |
12 | import { HttpClientBackendService } from './http-client-backend.service';
13 |
14 | // Internal - Creates the in-mem backend for the HttpClient module
15 | // AoT requires factory to be exported
16 | export function httpClientInMemBackendServiceFactory(
17 | dbService: InMemoryDbService,
18 | options: InMemoryBackendConfig,
19 | xhrFactory: XhrFactory,
20 | ): HttpBackend {
21 | const backend: any = new HttpClientBackendService(dbService, options, xhrFactory);
22 | return backend;
23 | }
24 |
25 | @NgModule({})
26 | export class HttpClientInMemoryWebApiModule {
27 | /**
28 | * Redirect the Angular `HttpClient` XHR calls
29 | * to in-memory data store that implements `InMemoryDbService`.
30 | * with class that implements InMemoryDbService and creates an in-memory database.
31 | *
32 | * Usually imported in the root application module.
33 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
34 | *
35 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
36 | * @param {InMemoryBackendConfigArgs} [options]
37 | *
38 | * @example
39 | * HttpInMemoryWebApiModule.forRoot(dbCreator);
40 | * HttpInMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
41 | */
42 | static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs):
43 | ModuleWithProviders {
44 | return {
45 | ngModule: HttpClientInMemoryWebApiModule,
46 | providers: [
47 | { provide: InMemoryDbService, useClass: dbCreator },
48 | { provide: InMemoryBackendConfig, useValue: options },
49 |
50 | { provide: HttpBackend,
51 | useFactory: httpClientInMemBackendServiceFactory,
52 | deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory]}
53 | ]
54 | };
55 | }
56 | /**
57 | *
58 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
59 | * Same as `forRoot`.
60 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
61 | */
62 | static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs):
63 | ModuleWithProviders {
64 | return HttpClientInMemoryWebApiModule.forRoot(dbCreator, options);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/in-mem/in-memory-web-api.module.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"class","statics":{"forRoot":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"ngModule":{"__symbol":0,"members":[]},"providers":[{"provide":{"__symbol":1,"members":[]},"useClass":{"__symbolic":"reference","name":"dbCreator"}},{"provide":{"__symbol":2,"members":[]},"useValue":{"__symbolic":"reference","name":"options"}},{"provide":{"__symbol":3,"members":[]},"useFactory":{"__symbol":4,"members":[]},"deps":[{"__symbol":1,"members":[]},{"__symbol":2,"members":[]},{"__symbol":5,"members":[]}]}]}},"forFeature":{"__symbolic":"function","parameters":["dbCreator","options"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbol":0,"members":[]},"member":"forRoot"},"arguments":[{"__symbolic":"reference","name":"dbCreator"},{"__symbolic":"reference","name":"options"}]}}}},"type":{"summaryKind":2,"type":{"reference":{"__symbol":0,"members":[]},"diDeps":[],"lifecycleHooks":[]},"entryComponents":[],"providers":[],"modules":[{"reference":{"__symbol":0,"members":[]},"diDeps":[],"lifecycleHooks":[]}],"exportedDirectives":[],"exportedPipes":[]}}],"symbols":[{"__symbol":0,"name":"InMemoryWebApiModule","filePath":"./in-memory-web-api.module"},{"__symbol":1,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":2,"name":"InMemoryBackendConfig","filePath":"./interfaces"},{"__symbol":3,"name":"HttpBackend","filePath":"@angular/common/http/http"},{"__symbol":4,"name":"httpClientInMemBackendServiceFactory","filePath":"./http-client-in-memory-web-api.module"},{"__symbol":5,"name":"XhrFactory","filePath":"@angular/common/http/http"}]}
--------------------------------------------------------------------------------
/src/in-mem/in-memory-web-api.module.ts:
--------------------------------------------------------------------------------
1 | ////// For apps with both Http and HttpClient ////
2 |
3 | import { Injector, NgModule, ModuleWithProviders, Type } from '@angular/core';
4 | import { HttpBackend, XhrFactory } from '@angular/common/http';
5 |
6 | import {
7 | InMemoryBackendConfigArgs,
8 | InMemoryBackendConfig,
9 | InMemoryDbService
10 | } from './interfaces';
11 |
12 | import { httpClientInMemBackendServiceFactory } from './http-client-in-memory-web-api.module';
13 |
14 | @NgModule({})
15 | export class InMemoryWebApiModule {
16 | /**
17 | * Redirect BOTH Angular `Http` and `HttpClient` XHR calls
18 | * to in-memory data store that implements `InMemoryDbService`.
19 | * with class that implements InMemoryDbService and creates an in-memory database.
20 | *
21 | * Usually imported in the root application module.
22 | * Can import in a lazy feature module too, which will shadow modules loaded earlier
23 | *
24 | * @param {Type} dbCreator - Class that creates seed data for in-memory database. Must implement InMemoryDbService.
25 | * @param {InMemoryBackendConfigArgs} [options]
26 | *
27 | * @example
28 | * InMemoryWebApiModule.forRoot(dbCreator);
29 | * InMemoryWebApiModule.forRoot(dbCreator, {useValue: {delay:600}});
30 | */
31 | static forRoot(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders {
32 | return {
33 | ngModule: InMemoryWebApiModule,
34 | providers: [
35 | { provide: InMemoryDbService, useClass: dbCreator },
36 | { provide: InMemoryBackendConfig, useValue: options },
37 |
38 |
39 | { provide: HttpBackend,
40 | useFactory: httpClientInMemBackendServiceFactory,
41 | deps: [InMemoryDbService, InMemoryBackendConfig, XhrFactory]}
42 | ]
43 | };
44 | }
45 |
46 | /**
47 | *
48 | * Enable and configure the in-memory web api in a lazy-loaded feature module.
49 | * Same as `forRoot`.
50 | * This is a feel-good method so you can follow the Angular style guide for lazy-loaded modules.
51 | */
52 | static forFeature(dbCreator: Type, options?: InMemoryBackendConfigArgs): ModuleWithProviders {
53 | return InMemoryWebApiModule.forRoot(dbCreator, options);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/in-mem/index.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbol":1,"members":[]}},{"symbol":{"__symbol":2,"members":[]},"metadata":{"__symbol":3,"members":[]}},{"symbol":{"__symbol":4,"members":[]},"metadata":{"__symbol":5,"members":[]}},{"symbol":{"__symbol":6,"members":[]},"metadata":{"__symbol":7,"members":[]}},{"symbol":{"__symbol":8,"members":[]},"metadata":{"__symbol":9,"members":[]}},{"symbol":{"__symbol":10,"members":[]},"metadata":{"__symbol":11,"members":[]}},{"symbol":{"__symbol":12,"members":[]},"metadata":{"__symbol":13,"members":[]}},{"symbol":{"__symbol":14,"members":[]},"metadata":{"__symbol":15,"members":[]}},{"symbol":{"__symbol":16,"members":[]},"metadata":{"__symbol":17,"members":[]}},{"symbol":{"__symbol":18,"members":[]},"metadata":{"__symbol":19,"members":[]}},{"symbol":{"__symbol":20,"members":[]},"metadata":{"__symbol":21,"members":[]}},{"symbol":{"__symbol":22,"members":[]},"metadata":{"__symbol":23,"members":[]}},{"symbol":{"__symbol":24,"members":[]},"metadata":{"__symbol":25,"members":[]}},{"symbol":{"__symbol":26,"members":[]},"metadata":{"__symbol":27,"members":[]}},{"symbol":{"__symbol":28,"members":[]},"metadata":{"__symbol":29,"members":[]}},{"symbol":{"__symbol":30,"members":[]},"metadata":{"__symbol":31,"members":[]}},{"symbol":{"__symbol":32,"members":[]},"metadata":{"__symbol":33,"members":[]}},{"symbol":{"__symbol":34,"members":[]},"metadata":{"__symbol":35,"members":[]}},{"symbol":{"__symbol":36,"members":[]},"metadata":{"__symbol":37,"members":[]}},{"symbol":{"__symbol":38,"members":[]},"metadata":{"__symbol":39,"members":[]}},{"symbol":{"__symbol":40,"members":[]},"metadata":{"__symbol":41,"members":[]}},{"symbol":{"__symbol":42,"members":[]},"metadata":{"__symbol":43,"members":[]}},{"symbol":{"__symbol":44,"members":[]},"metadata":{"__symbol":45,"members":[]}}],"symbols":[{"__symbol":0,"name":"BackendService","filePath":"./index"},{"__symbol":1,"name":"BackendService","filePath":"./backend.service"},{"__symbol":2,"name":"STATUS","filePath":"./index"},{"__symbol":3,"name":"STATUS","filePath":"./http-status-codes"},{"__symbol":4,"name":"STATUS_CODE_INFO","filePath":"./index"},{"__symbol":5,"name":"STATUS_CODE_INFO","filePath":"./http-status-codes"},{"__symbol":6,"name":"getStatusText","filePath":"./index"},{"__symbol":7,"name":"getStatusText","filePath":"./http-status-codes"},{"__symbol":8,"name":"isSuccess","filePath":"./index"},{"__symbol":9,"name":"isSuccess","filePath":"./http-status-codes"},{"__symbol":10,"name":"HttpClientBackendService","filePath":"./index"},{"__symbol":11,"name":"HttpClientBackendService","filePath":"./http-client-backend.service"},{"__symbol":12,"name":"InMemoryWebApiModule","filePath":"./index"},{"__symbol":13,"name":"InMemoryWebApiModule","filePath":"./in-memory-web-api.module"},{"__symbol":14,"name":"httpClientInMemBackendServiceFactory","filePath":"./index"},{"__symbol":15,"name":"httpClientInMemBackendServiceFactory","filePath":"./http-client-in-memory-web-api.module"},{"__symbol":16,"name":"HttpClientInMemoryWebApiModule","filePath":"./index"},{"__symbol":17,"name":"HttpClientInMemoryWebApiModule","filePath":"./http-client-in-memory-web-api.module"},{"__symbol":18,"name":"HeadersCore","filePath":"./index"},{"__symbol":19,"name":"HeadersCore","filePath":"./interfaces"},{"__symbol":20,"name":"InMemoryDbService","filePath":"./index"},{"__symbol":21,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":22,"name":"InMemoryBackendConfigArgs","filePath":"./index"},{"__symbol":23,"name":"InMemoryBackendConfigArgs","filePath":"./interfaces"},{"__symbol":24,"name":"InMemoryBackendConfig","filePath":"./index"},{"__symbol":25,"name":"InMemoryBackendConfig","filePath":"./interfaces"},{"__symbol":26,"name":"parseUri","filePath":"./index"},{"__symbol":27,"name":"parseUri","filePath":"./interfaces"},{"__symbol":28,"name":"ParsedRequestUrl","filePath":"./index"},{"__symbol":29,"name":"ParsedRequestUrl","filePath":"./interfaces"},{"__symbol":30,"name":"PassThruBackend","filePath":"./index"},{"__symbol":31,"name":"PassThruBackend","filePath":"./interfaces"},{"__symbol":32,"name":"removeTrailingSlash","filePath":"./index"},{"__symbol":33,"name":"removeTrailingSlash","filePath":"./interfaces"},{"__symbol":34,"name":"RequestCore","filePath":"./index"},{"__symbol":35,"name":"RequestCore","filePath":"./interfaces"},{"__symbol":36,"name":"RequestInfo","filePath":"./index"},{"__symbol":37,"name":"RequestInfo","filePath":"./interfaces"},{"__symbol":38,"name":"RequestInfoUtilities","filePath":"./index"},{"__symbol":39,"name":"RequestInfoUtilities","filePath":"./interfaces"},{"__symbol":40,"name":"ResponseInterceptor","filePath":"./index"},{"__symbol":41,"name":"ResponseInterceptor","filePath":"./interfaces"},{"__symbol":42,"name":"ResponseOptions","filePath":"./index"},{"__symbol":43,"name":"ResponseOptions","filePath":"./interfaces"},{"__symbol":44,"name":"UriInfo","filePath":"./index"},{"__symbol":45,"name":"UriInfo","filePath":"./interfaces"}]}
--------------------------------------------------------------------------------
/src/in-mem/index.ts:
--------------------------------------------------------------------------------
1 | export * from './backend.service';
2 | export * from './http-status-codes';
3 | export * from './http-client-backend.service';
4 | export * from './in-memory-web-api.module';
5 | export * from './http-client-in-memory-web-api.module';
6 | export * from './interfaces';
7 |
--------------------------------------------------------------------------------
/src/in-mem/interfaces.ngsummary.json:
--------------------------------------------------------------------------------
1 | {"moduleName":null,"summaries":[{"symbol":{"__symbol":0,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":1,"members":[]},"metadata":{"__symbolic":"class","members":{"createDb":[{"__symbolic":"method"}]}}},{"symbol":{"__symbol":2,"members":[]},"metadata":{"__symbolic":"class"}},{"symbol":{"__symbol":3,"members":[]},"metadata":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbol":2,"members":[]}]}]}},"type":{"summaryKind":3,"type":{"reference":{"__symbol":3,"members":[]},"diDeps":[{"isAttribute":false,"isHost":false,"isSelf":false,"isSkipSelf":false,"isOptional":false,"token":{"identifier":{"reference":{"__symbol":2,"members":[]}}}}],"lifecycleHooks":[]}}},{"symbol":{"__symbol":4,"members":[]},"metadata":{"__symbolic":"function"}},{"symbol":{"__symbol":5,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":6,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":7,"members":[]},"metadata":{"__symbolic":"function","parameters":["path"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbolic":"reference","name":"path"},"member":"replace"},"arguments":[{"__symbolic":"error","message":"Expression form not supported","fileName":"src\\in-mem\\interfaces.ts"},""]}}},{"symbol":{"__symbol":8,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":9,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":10,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":11,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":12,"members":[]},"metadata":{"__symbolic":"interface"}},{"symbol":{"__symbol":13,"members":[]},"metadata":{"__symbolic":"interface"}}],"symbols":[{"__symbol":0,"name":"HeadersCore","filePath":"./interfaces"},{"__symbol":1,"name":"InMemoryDbService","filePath":"./interfaces"},{"__symbol":2,"name":"InMemoryBackendConfigArgs","filePath":"./interfaces"},{"__symbol":3,"name":"InMemoryBackendConfig","filePath":"./interfaces"},{"__symbol":4,"name":"parseUri","filePath":"./interfaces"},{"__symbol":5,"name":"ParsedRequestUrl","filePath":"./interfaces"},{"__symbol":6,"name":"PassThruBackend","filePath":"./interfaces"},{"__symbol":7,"name":"removeTrailingSlash","filePath":"./interfaces"},{"__symbol":8,"name":"RequestCore","filePath":"./interfaces"},{"__symbol":9,"name":"RequestInfo","filePath":"./interfaces"},{"__symbol":10,"name":"RequestInfoUtilities","filePath":"./interfaces"},{"__symbol":11,"name":"ResponseInterceptor","filePath":"./interfaces"},{"__symbol":12,"name":"ResponseOptions","filePath":"./interfaces"},{"__symbol":13,"name":"UriInfo","filePath":"./interfaces"}]}
--------------------------------------------------------------------------------
/src/in-mem/interfaces.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Observable } from 'rxjs';
3 |
4 | /**
5 | * Minimum definition needed by base class
6 | */
7 | export interface HeadersCore {
8 | set(name: string, value: string): void | any;
9 | }
10 |
11 | /**
12 | * Interface for a class that creates an in-memory database
13 | *
14 | * Its `createDb` method creates a hash of named collections that represents the database
15 | *
16 | * For maximum flexibility, the service may define HTTP method overrides.
17 | * Such methods must match the spelling of an HTTP method in lower case (e.g, "get").
18 | * If a request has a matching method, it will be called as in
19 | * `get(info: requestInfo, db: {})` where `db` is the database object described above.
20 | */
21 | export abstract class InMemoryDbService {
22 | /**
23 | * Creates an in-memory "database" hash whose keys are collection names
24 | * and whose values are arrays of collection objects to return or update.
25 | *
26 | * returns Observable of the database because could have to create it asynchronously.
27 | *
28 | * This method must be safe to call repeatedly.
29 | * Each time it should return a new object with new arrays containing new item objects.
30 | * This condition allows the in-memory backend service to mutate the collections
31 | * and their items without touching the original source data.
32 | *
33 | * The in-mem backend service calls this method without a value the first time.
34 | * The service calls it with the `RequestInfo` when it receives a POST `commands/resetDb` request.
35 | * Your InMemoryDbService can adjust its behavior accordingly.
36 | */
37 | abstract createDb(reqInfo?: RequestInfo): {} | Observable<{}> | Promise<{}>;
38 | }
39 |
40 | /**
41 | * Interface for InMemoryBackend configuration options
42 | */
43 | export abstract class InMemoryBackendConfigArgs {
44 | /**
45 | * The base path to the api, e.g, 'api/'.
46 | * If not specified than `parseRequestUrl` assumes it is the first path segment in the request.
47 | */
48 | apiBase?: string;
49 | /**
50 | * false (default) if search match should be case insensitive
51 | */
52 | caseSensitiveSearch?: boolean;
53 | /**
54 | * false (default) put content directly inside the response body.
55 | * true: encapsulate content in a `data` property inside the response body, `{ data: ... }`.
56 | */
57 | dataEncapsulation?: boolean;
58 | /**
59 | * delay (in ms) to simulate latency
60 | */
61 | delay?: number;
62 | /**
63 | * false (default) should 204 when object-to-delete not found; true: 404
64 | */
65 | delete404?: boolean;
66 | /**
67 | * host for this service, e.g., 'localhost'
68 | */
69 | host?: string;
70 | /**
71 | * false (default) should pass unrecognized request URL through to original backend; true: 404
72 | */
73 | passThruUnknownUrl?: boolean;
74 | /**
75 | * true (default) should NOT return the item (204) after a POST. false: return the item (200).
76 | */
77 | post204?: boolean;
78 | /**
79 | * false (default) should NOT update existing item with POST. false: OK to update.
80 | */
81 | post409?: boolean;
82 | /**
83 | * true (default) should NOT return the item (204) after a POST. false: return the item (200).
84 | */
85 | put204?: boolean;
86 | /**
87 | * false (default) if item not found, create as new item; false: should 404.
88 | */
89 | put404?: boolean;
90 | /**
91 | * root path _before_ any API call, e.g., ''
92 | */
93 | rootPath?: string;
94 | }
95 |
96 | /////////////////////////////////
97 | /**
98 | * InMemoryBackendService configuration options
99 | * Usage:
100 | * InMemoryWebApiModule.forRoot(InMemHeroService, {delay: 600})
101 | *
102 | * or if providing separately:
103 | * provide(InMemoryBackendConfig, {useValue: {delay: 600}}),
104 | */
105 | @Injectable()
106 | export class InMemoryBackendConfig implements InMemoryBackendConfigArgs {
107 | constructor(config: InMemoryBackendConfigArgs = {}) {
108 | Object.assign(this, {
109 | // default config:
110 | caseSensitiveSearch: false,
111 | dataEncapsulation: false, // do NOT wrap content within an object with a `data` property
112 | delay: 500, // simulate latency by delaying response
113 | delete404: false, // don't complain if can't find entity to delete
114 | passThruUnknownUrl: false, // 404 if can't process URL
115 | post204: true, // don't return the item after a POST
116 | post409: false, // don't update existing item with that ID
117 | put204: true, // don't return the item after a PUT
118 | put404: false, // create new item if PUT item with that ID not found
119 | apiBase: undefined, // assumed to be the first path segment
120 | host: undefined, // default value is actually set in InMemoryBackendService ctor
121 | rootPath: undefined // default value is actually set in InMemoryBackendService ctor
122 | }, config);
123 | }
124 | }
125 |
126 | /** Return information (UriInfo) about a URI */
127 | export function parseUri(str: string): UriInfo {
128 | // Adapted from parseuri package - http://blog.stevenlevithan.com/archives/parseuri
129 | // tslint:disable-next-line:max-line-length
130 | const URL_REGEX = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
131 | const m = URL_REGEX.exec(str);
132 | const uri: UriInfo = {
133 | source: '',
134 | protocol: '',
135 | authority: '',
136 | userInfo: '',
137 | user: '',
138 | password: '',
139 | host: '',
140 | port: '',
141 | relative: '',
142 | path: '',
143 | directory: '',
144 | file: '',
145 | query: '',
146 | anchor: ''
147 | };
148 | const keys = Object.keys(uri);
149 | let i = keys.length;
150 |
151 | while (i--) { uri[keys[i]] = m[i] || ''; }
152 | return uri;
153 | }
154 |
155 | /**
156 | *
157 | * Interface for the result of the `parseRequestUrl` method:
158 | * Given URL "http://localhost:8080/api/customers/42?foo=1 the default implementation returns
159 | * base: 'api/'
160 | * collectionName: 'customers'
161 | * id: '42'
162 | * query: this.createQuery('foo=1')
163 | * resourceUrl: 'http://localhost/api/customers/'
164 | */
165 | export interface ParsedRequestUrl {
166 | apiBase: string; // the slash-terminated "base" for api requests (e.g. `api/`)
167 | collectionName: string; // the name of the collection of data items (e.g.,`customers`)
168 | id: string; // the (optional) id of the item in the collection (e.g., `42`)
169 | query: Map; // the query parameters;
170 | resourceUrl: string; // the effective URL for the resource (e.g., 'http://localhost/api/customers/')
171 | }
172 |
173 | export interface PassThruBackend {
174 | /**
175 | * Handle an HTTP request and return an Observable of HTTP response
176 | * Both the request type and the response type are determined by the supporting HTTP library.
177 | */
178 | handle(req: any): Observable;
179 | }
180 |
181 | export function removeTrailingSlash(path: string) {
182 | return path.replace(/\/$/, '');
183 | }
184 |
185 | /**
186 | * Minimum definition needed by base class
187 | */
188 | export interface RequestCore {
189 | url: string; // request URL
190 | urlWithParams?: string; // request URL with query parameters added by `HttpParams`
191 | }
192 |
193 | /**
194 | * Interface for object w/ info about the current request url
195 | * extracted from an Http Request.
196 | * Also holds utility methods and configuration data from this service
197 | */
198 | export interface RequestInfo {
199 | req: RequestCore; // concrete type depends upon the Http library
200 | apiBase: string;
201 | collectionName: string;
202 | collection: any;
203 | headers: HeadersCore;
204 | method: string;
205 | id: any;
206 | query: Map;
207 | resourceUrl: string;
208 | url: string; // request URL
209 | utils: RequestInfoUtilities;
210 | }
211 |
212 | /**
213 | * Interface for utility methods from this service instance.
214 | * Useful within an HTTP method override
215 | */
216 | export interface RequestInfoUtilities {
217 | /**
218 | * Create a cold response Observable from a factory for ResponseOptions
219 | * the same way that the in-mem backend service does.
220 | * @param resOptionsFactory - creates ResponseOptions when observable is subscribed
221 | * @param withDelay - if true (default), add simulated latency delay from configuration
222 | */
223 | createResponse$: (resOptionsFactory: () => ResponseOptions) => Observable;
224 |
225 | /**
226 | * Find first instance of item in collection by `item.id`
227 | * @param collection
228 | * @param id
229 | */
230 | findById(collection: T[], id: any): T;
231 |
232 | /** return the current, active configuration which is a blend of defaults and overrides */
233 | getConfig(): InMemoryBackendConfigArgs;
234 |
235 | /** Get the in-mem service's copy of the "database" */
236 | getDb(): {};
237 |
238 | /** Get JSON body from the request object */
239 | getJsonBody(req: any): any;
240 |
241 | /** Get location info from a url, even on server where `document` is not defined */
242 | getLocation(url: string): UriInfo;
243 |
244 | /** Get (or create) the "real" backend */
245 | getPassThruBackend(): PassThruBackend;
246 |
247 | /**
248 | * return true if can determine that the collection's `item.id` is a number
249 | * */
250 | isCollectionIdNumeric(collection: T[], collectionName: string): boolean;
251 |
252 | /**
253 | * Parses the request URL into a `ParsedRequestUrl` object.
254 | * Parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.
255 | */
256 | parseRequestUrl(url: string): ParsedRequestUrl;
257 | }
258 |
259 | /**
260 | * Provide a `responseInterceptor` method of this type in your `inMemDbService` to
261 | * morph the response options created in the `collectionHandler`.
262 | */
263 | export type ResponseInterceptor = (res: ResponseOptions, ri: RequestInfo) => ResponseOptions;
264 |
265 | export interface ResponseOptions {
266 | /**
267 | * String, Object, ArrayBuffer or Blob representing the body of the {@link Response}.
268 | */
269 | body?: string | Object | ArrayBuffer | Blob;
270 |
271 | /**
272 | * Response headers
273 | */
274 | headers?: HeadersCore;
275 |
276 | /**
277 | * Http {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html status code}
278 | * associated with the response.
279 | */
280 | status?: number;
281 |
282 | /**
283 | * Status text for the status code
284 | */
285 | statusText?: string;
286 | /**
287 | * request url
288 | */
289 | url?: string;
290 | }
291 |
292 | /** Interface of information about a Uri */
293 | export interface UriInfo {
294 | source: string;
295 | protocol: string;
296 | authority: string;
297 | userInfo: string;
298 | user: string;
299 | password: string;
300 | host: string;
301 | port: string;
302 | relative: string;
303 | path: string;
304 | directory: string;
305 | file: string;
306 | query: string;
307 | anchor: string;
308 | }
309 |
--------------------------------------------------------------------------------
/src/systemjs-angular-loader.js:
--------------------------------------------------------------------------------
1 | var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
2 | var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
3 | var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
4 |
5 | module.exports.translate = function(load){
6 | if (load.source.indexOf('moduleId') != -1) return load;
7 |
8 | var url = document.createElement('a');
9 | url.href = load.address;
10 |
11 | var basePathParts = url.pathname.split('/');
12 |
13 | basePathParts.pop();
14 | var basePath = basePathParts.join('/');
15 |
16 | var baseHref = document.createElement('a');
17 | baseHref.href = this.baseURL;
18 | baseHref = baseHref.pathname;
19 |
20 | if (!baseHref.startsWith('/base/')) { // it is not karma
21 | basePath = basePath.replace(baseHref, '');
22 | }
23 |
24 | load.source = load.source
25 | .replace(templateUrlRegex, function(match, quote, url){
26 | var resolvedUrl = url;
27 |
28 | if (url.startsWith('.')) {
29 | resolvedUrl = basePath + url.substr(1);
30 | }
31 |
32 | return 'templateUrl: "' + resolvedUrl + '"';
33 | })
34 | .replace(stylesRegex, function(match, relativeUrls) {
35 | var urls = [];
36 |
37 | while ((match = stringRegex.exec(relativeUrls)) !== null) {
38 | if (match[2].startsWith('.')) {
39 | urls.push('"' + basePath + match[2].substr(1) + '"');
40 | } else {
41 | urls.push('"' + match[2] + '"');
42 | }
43 | }
44 |
45 | return "styleUrls: [" + urls.join(', ') + "]";
46 | });
47 |
48 | return load;
49 | };
50 |
--------------------------------------------------------------------------------
/src/systemjs.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * System configuration for Angular samples
3 | * Adjust as necessary for your application needs.
4 | */
5 | (function (global) {
6 | System.config({
7 | paths: {
8 | // paths serve as alias
9 | 'npm:': 'node_modules/'
10 | },
11 | // map tells the System loader where to look for things
12 | map: {
13 | // our app is within the app folder
14 | 'app': 'app',
15 |
16 | // angular bundles
17 | '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js',
18 | '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
19 | '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
20 | '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
21 | '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
22 | '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
23 | '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
24 | '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',
25 | '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
26 | '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
27 | '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
28 | '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
29 | '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
30 | '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
31 |
32 | // other libraries
33 | 'rxjs': 'npm:rxjs',
34 | 'tslib': 'npm:tslib/tslib.js',
35 | 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
36 | },
37 | // packages tells the System loader how to load when no filename and/or no extension
38 | packages: {
39 | 'app': {
40 | main: './main.js',
41 | defaultExtension: 'js',
42 | meta: {
43 | './*.js': {
44 | loader: 'systemjs-angular-loader.js'
45 | }
46 | }
47 | },
48 | 'rxjs': {
49 | main: 'index.js'
50 | },
51 | 'rxjs/operators': {
52 | main: 'index.js'
53 | }
54 | }
55 | });
56 | })(this);
57 |
--------------------------------------------------------------------------------
/src/testing/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Fail a Jasmine test such that it displays the error object,
3 | * typically passed in the error path of an Observable.subscribe()
4 | * @param err - the error object
5 | */
6 | export function failure(err: any) {
7 | fail(JSON.stringify(err));
8 | }
9 |
--------------------------------------------------------------------------------
/src/testing/jasmine-ajax.spec.ts:
--------------------------------------------------------------------------------
1 | // Confirm that the jasmine ajax testing library works in this project stand-alone.
2 | // These tests are copied from the documentation
3 | // https://jasmine.github.io/edge/ajax.html
4 | // See karma.conf and package.json changes related to using this jasmine plugin
5 | // https://www.npmjs.com/package/karma-jasmine-ajax
6 |
7 | describe('Jasmine ajax mocking proof-of-life', () => {
8 |
9 | describe('suite wide usage', () => {
10 |
11 | beforeEach(function() {
12 | jasmine.Ajax.install();
13 | });
14 |
15 | afterEach(function() {
16 | jasmine.Ajax.uninstall();
17 | });
18 |
19 | it('specifying response when you need it', () => {
20 | const doneFn = jasmine.createSpy('success');
21 |
22 | const xhr = new XMLHttpRequest();
23 | xhr.onreadystatechange = function(args) {
24 | if (this.readyState === this.DONE) {
25 | doneFn(this.responseText);
26 | }
27 | };
28 |
29 | xhr.open('GET', '/some/cool/url');
30 | xhr.send();
31 |
32 | expect(jasmine.Ajax.requests.mostRecent().url).toBe('/some/cool/url');
33 | expect(doneFn).not.toHaveBeenCalled();
34 |
35 | jasmine.Ajax.requests.mostRecent().respondWith({
36 | 'status': 200,
37 | 'contentType': 'text/plain',
38 | 'responseText': 'awesome response'
39 | });
40 |
41 | expect(doneFn).toHaveBeenCalledWith('awesome response');
42 | });
43 |
44 | it('allows responses to be setup ahead of time', () => {
45 | const doneFn = jasmine.createSpy('success');
46 |
47 | jasmine.Ajax.stubRequest('/another/url').andReturn({
48 | 'responseText': 'immediate response'
49 | });
50 | const xhr = new XMLHttpRequest();
51 | xhr.onreadystatechange = function(args) {
52 | if (this.readyState === this.DONE) {
53 | doneFn(this.responseText);
54 | }
55 | };
56 |
57 | xhr.open('GET', '/another/url');
58 | xhr.send();
59 |
60 | expect(doneFn).toHaveBeenCalledWith('immediate response');
61 | });
62 |
63 | });
64 |
65 | it('allows use in a single spec', () => {
66 | const doneFn = jasmine.createSpy('success');
67 | jasmine.Ajax.withMock(function() {
68 | const xhr = new XMLHttpRequest();
69 | xhr.onreadystatechange = function(args) {
70 | if (this.readyState === this.DONE) {
71 | doneFn(this.responseText);
72 | }
73 | };
74 |
75 | xhr.open('GET', '/some/cool/url');
76 | xhr.send();
77 |
78 | expect(doneFn).not.toHaveBeenCalled();
79 |
80 | jasmine.Ajax.requests.mostRecent().respondWith({
81 | 'status': 200,
82 | 'responseText': 'in spec response'
83 | });
84 |
85 | expect(doneFn).toHaveBeenCalledWith('in spec response');
86 | });
87 | });
88 |
89 | it('allows use in a single spec (json response)', () => {
90 | const doneFn = jasmine.createSpy('success');
91 | jasmine.Ajax.withMock(function() {
92 | const xhr = new XMLHttpRequest();
93 | xhr.onreadystatechange = function(args) {
94 | if (this.readyState === this.DONE) {
95 | doneFn(this.response);
96 | }
97 | };
98 |
99 | xhr.open('GET', '/some/cool/url');
100 | xhr.send();
101 |
102 | expect(doneFn).not.toHaveBeenCalled();
103 |
104 | const data = { data: [{ id: 42, name: 'Dude' }] };
105 | const expectedResponse = JSON.stringify(data);
106 |
107 | jasmine.Ajax.requests.mostRecent().respondWith({
108 | 'status': 200,
109 | 'contentType': 'application/json',
110 | 'response': expectedResponse
111 | });
112 |
113 | expect(doneFn).toHaveBeenCalledWith(expectedResponse);
114 | });
115 | });
116 |
117 | });
118 |
--------------------------------------------------------------------------------
/tsconfig-ngc.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "es2015",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "inlineSources": true,
8 | "declaration": true,
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "lib": [ "es2015", "dom" ],
12 | "noImplicitAny": true,
13 | "suppressImplicitAnyIndexErrors": true
14 | },
15 | "files": [
16 | "src/in-mem/index.ts"
17 | ],
18 | "angularCompilerOptions": {
19 | "genDir": "aot",
20 | "skipMetadataEmit" : false
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "moduleResolution": "node",
6 | "sourceMap": true,
7 | "inlineSources": true,
8 | "declaration": true,
9 | "emitDecoratorMetadata": true,
10 | "experimentalDecorators": true,
11 | "lib": [ "es2015", "dom" ],
12 | "noImplicitAny": true,
13 | "suppressImplicitAnyIndexErrors": true,
14 | "strictPropertyInitialization": false
15 | },
16 | "exclude": [
17 | "node_modules",
18 | "typings/main",
19 | "typings/main.d.ts",
20 | "**/*.d.ts"
21 | ],
22 | "angularCompilerOptions": {
23 | "genDir": "aot",
24 | "skipMetadataEmit" : false
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------