• This repository has been archived on 11/Jan/2023
  • Stars
    star
    1,172
  • Rank 39,881 (Top 0.8 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

The code for this project has moved to the angular/angular repo. This repo is now archived.

Angular in-memory-web-api

Build Status

An in-memory web api for Angular demos and tests that emulates CRUD operations over a RESTy API.

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.

See Austin McDaniel's article for a quick introduction.

It used to work and now it doesn't :-(

Perhaps you installed a new version of this library? Check the CHANGELOG.md for breaking changes that may have affected your app.

If that doesn't explain it, create an issue on github, preferably with a small repro.

Use cases

  • Demo apps that need to simulate CRUD data persistence operations without a real server. You won't have to build and start a test server.

  • Whip up prototypes and proofs of concept.

  • Share examples with the community in a web coding environment such as Plunker or CodePen. Create Angular issues and StackOverflow answers supported by live code.

  • Simulate operations against data collections that aren't yet implemented on your dev/test server. You can pass requests thru to the dev/test server for collections that are supported.

  • Write unit test apps that read and write data. Avoid the hassle of intercepting multiple http calls and manufacturing sequences of responses. The in-memory data store resets for each test so there is no cross-test data pollution.

  • End-to-end tests. If you can toggle the app into test mode using the in-memory web api, you won't disturb the real database. This can be especially useful for CI (continuous integration) builds.

LIMITATIONS

The in-memory-web-api exists primarily to support the Angular documentation. It is not supposed to emulate every possible real world web API and is not intended for production use.

Most importantly, it is always experimental. We will make breaking changes and we won't feel bad about it because this is a development tool, not a production product. We do try to tell you about such changes in the CHANGELOG.md and we fix bugs as fast as we can.

HTTP request handling

This in-memory web api service processes an HTTP request and returns an Observable of HTTP Response object in the manner of a RESTy web api. It natively handles URI patterns in the form :base/:collectionName/:id?

Examples:

  // for requests to an `api` base URL that gets heroes from a 'heroes' collection 
  GET api/heroes          // all heroes
  GET api/heroes/42       // the hero with id=42
  GET api/heroes?name=^j  // 'j' is a regex; returns heroes whose name starting with 'j' or 'J'
  GET api/heroes.json/42  // ignores the ".json"

The in-memory web api service processes these requests against a "database" - a set of named collections - that you define during setup.

Basic setup

Create an InMemoryDataService class that implements InMemoryDbService.

At minimum it must implement createDb which creates a "database" hash whose keys are collection names and whose values are arrays of collection objects to return or update. For example:

import { InMemoryDbService } from 'angular-in-memory-web-api';

export class InMemHeroService implements InMemoryDbService {
  createDb() {
    let heroes = [
      { id: 1, name: 'Windstorm' },
      { id: 2, name: 'Bombasto' },
      { id: 3, name: 'Magneta' },
      { id: 4, name: 'Tornado' }
    ];
    return {heroes};
  }
}

Notes

  • The in-memory web api library currently assumes that every collection has a primary key called id.

  • The createDb method can be synchronous or asynchronous. It would have to be asynchronous if you initialized your in-memory database service from a JSON file. Return the database object, an observable of that object, or a promise of that object. The tests include an example of all three.

  • The in-memory web api calls your InMemoryDbService data service class's createDb method on two occasions.

    1. when it handles the first HTTP request
    2. when it receives a resetdb command.

    In the command case, the service passes in a RequestInfo object, enabling the createDb logic to adjust its behavior per the client request. See the tests for examples.

Import the in-memory web api module

Register your data store service implementation with the HttpClientInMemoryWebApiModule in your root AppModule.imports calling the forRoot static method with this service class and an optional configuration object:

import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';

import { InMemHeroService } from '../app/hero.service';

@NgModule({
 imports: [
   HttpClientModule,
   HttpClientInMemoryWebApiModule.forRoot(InMemHeroService),
   ...
 ],
 ...
})
export class AppModule { ... }

Notes

  • Always import the HttpClientInMemoryWebApiModule after the HttpClientModule to ensure that the in-memory backend provider supersedes the Angular version.

  • You can setup the in-memory web api within a lazy loaded feature module by calling the .forFeature method as you would .forRoot.

  • In production, you want HTTP requests to go to the real server and probably have no need for the in-memory provider. CLI-based apps can exclude the provider in production builds like this:

    imports: [
      HttpClientModule,
      environment.production ?
        [] : HttpClientInMemoryWebApiModule.forRoot(InMemHeroService)
      ...
    ]

Examples

The tests (src/app/*.spec.ts files) in the github repository are a good place to learn how to setup and use this in-memory web api library.

See also the example source code in the official Angular.io documentation such as the HttpClient guide and the Tour of Heroes.

Advanced Features

Some features are not readily apparent in the basic usage described above.

Configuration arguments

The InMemoryBackendConfigArgs defines a set of options. Add them as the second forRoot argument:

  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 500 }),

Read the InMemoryBackendConfigArgs interface to learn about these options.

Request evaluation order

This service can evaluate requests in multiple ways depending upon the configuration. Here's how it reasons:

  1. If it looks like a command, process as a command
  2. If the HTTP method is overridden, try the override.
  3. If the resource name (after the api base path) matches one of the configured collections, process that
  4. If not but the Config.passThruUnknownUrl flag is true, try to pass the request along to a real XHR.
  5. Return a 404.

See the handleRequest method implementation for details.

Default delayed response

By default this service adds a 500ms delay to all data requests to simulate round-trip latency.

Command requests have zero added delay as they concern in-memory service configuration and do not emulate real data requests.

You can change or eliminate the latency by setting a different delay value:

  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 0 }),    // no delay
  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 1500 }), // 1.5 second delay

Simple query strings

Pass custom filters as a regex pattern via query string. The query string defines which property and value to match.

Format: /app/heroes/?propertyName=regexPattern

The following example matches all names start with the letter 'j' or 'J' in the heroes collection.

/app/heroes/?name=^j

Search pattern matches are case insensitive by default. Set config.caseSensitiveSearch = true if needed.

Pass thru to a live server

If an existing, running remote server should handle requests for collections that are not in the in-memory database, set Config.passThruUnknownUrl: true. Then this service will forward unrecognized requests to the remote server via the Angular default XHR backend (it depends on whether your using Http or HttpClient).

Commands

The client may issue a command request to get configuration state from the in-memory web api service, reconfigure it, or reset the in-memory database.

When the last segment of the api base path is "commands", the collectionName is treated as the command.

Example URLs:

  commands/resetdb   // Reset the "database" to its original state
  commands/config    // Get or update this service's config object

Usage:

  http.post('commands/resetdb', undefined);
  http.get('commands/config');
  http.post('commands/config', '{"delay":1000}');

Command requests do not simulate real remote data access. They ignore the latency delay and respond as quickly as possible.

The resetDb command calls your InMemoryDbService data service's createDb method with the RequestInfo object, enabling the createDb logic to adjust its behavior per the client request.

In the following example, the client includes a reset option in the command request body:

http
  // Reset the database collections with the `clear` option
  .post('commands/resetDb', { clear: true }))

  // when command finishes, get heroes
  .concatMap(
    ()=> http.get<Data>('api/heroes')
        .map(data => data.data as Hero[])
  )

  // execute the request sequence and 
  // do something with the heroes
  .subscribe(...)

See the tests for other examples.

parseRequestUrl

The parseRequestUrl parses the request URL into a ParsedRequestUrl object. ParsedRequestUrl is a public interface whose properties guide the in-memory web api as it processes the request.

Default parseRequestUrl

Default parsing depends upon certain values of config: apiBase, host, and urlRoot. Read the source code for the complete story.

Configuring the apiBase yields the most interesting changes to parseRequestUrl behavior:

  • For apiBase=undefined and url='http://localhost/api/customers/42'

    {apiBase: 'api/', collectionName: 'customers', id: '42', ...}
  • For apiBase='some/api/root/' and url='http://localhost/some/api/root/customers'

    { apiBase: 'some/api/root/', collectionName: 'customers', id: undefined, ... }
  • For apiBase='/' and url='http://localhost/customers'

    { apiBase: '/', collectionName: 'customers', id: undefined, ... }

The actual api base segment values are ignored. Only the number of segments matters. The following api base strings are considered identical: 'a/b' ~ 'some/api/' ~ `two/segments'

This means that URLs that work with the in-memory web api may be rejected by the real server.

Custom parseRequestUrl

You can override the default parser by implementing a parseRequestUrl method in your InMemoryDbService.

The service calls your method with two arguments.

  1. url - the request URL string
  2. requestInfoUtils - utility methods in a RequestInfoUtilities object, including the default parser. Note that some values have not yet been set as they depend on the outcome of parsing.

Your method must either return a ParsedRequestUrl object or null|undefined, in which case the service uses the default parser. In this way you can intercept and parse some URLs and leave the others to the default parser.

Custom genId

Collection items are presumed to have a primary key property called id.

You can specify the id while adding a new item. The service will blindly use that id; it does not check for uniqueness.

If you do not specify the id, the service generates one via the genId method.

You can override the default id generator with a method called genId in your InMemoryDbService. Your method receives the new item's collection and collection name. It should return the generated id. If your generator returns null|undefined, the service uses the default generator.

responseInterceptor

You can change the response returned by the service's default HTTP methods. A typical reason to intercept is to add a header that your application is expecting.

To intercept responses, add a responseInterceptor method to your InMemoryDbService class. The service calls your interceptor like this:

responseOptions = this.responseInterceptor(responseOptions, requestInfo);

HTTP method interceptors

You may have HTTP requests that the in-memory web api can't handle properly.

You can override any HTTP method by implementing a method of that name in your InMemoryDbService.

Your method's name must be the same as the HTTP method name but all lowercase. The in-memory web api calls it with a RequestInfo object that contains request data and utility methods.

For example, if you implemented a get method, the web api would be called like this: yourInMemDbService["get"](requestInfo).

Your custom HTTP method must return either:

  • Observable<Response> - you handled the request and the response is available from this observable. It should be "cold".

  • null/undefined - you decided not to intervene, perhaps because you wish to intercept only certain paths for the given HTTP method. The service continues with its default processing of the HTTP request.

The RequestInfo is an interface defined in src/in-mem/interfaces.ts. Its members include:

req: Request;           // the request object from the client
collectionName: string; // calculated from the request url
collection: any[];      // the corresponding collection (if found)
id: any;                // the item `id` (if specified)
url: string;            // the url in the request
utils: RequestInfoUtilities; // helper functions

The functions in utils can help you analyze the request and compose a response.

In-memory Web Api Examples

The github repository demonstrates library usage with tested examples.

The HeroInMemDataService class (in src/app/hero-in-mem-data.service.ts) is a Hero-oriented InMemoryDbService such as you might see in an HTTP sample in the Angular documentation.

The HeroInMemDataOverrideService class (in src/app/hero-in-mem-data-override.service.ts) demonstrates a few ways to override methods of the base HeroInMemDataService.

The tests (see below) exercise these examples.

Build Instructions

Follow these steps for updating the library.

  • gulp bump - up the package version number.

  • update CHANGELOG.md to record the change. Call out breaking changes.

  • update README.md if usage or interfaces change.

  • consider updating the dependency versions in package.json.

  • npm install the new package(s) if you did.

  • npm list --depth=0 to make sure they really did install!

  • gulp clean to delete all generated files.

  • npm test to dev-build and run tests (see "Testing" below).

  • gulp build to build for distribution.

  • git add, commit, and push.

  • npm publish

  • Confirm that angular.io docs samples still work

  • Add two tags to the release commit in github

    • the version number
    • 'latest'

Testing

The "app" for this repo is not a real app. It's an Angular data service (HeroService) and a bunch of tests.

Note that the tsconfig.json produces a commonjs module. That's what Angular specs require. But when building for an app, it should be a es2015 module, as is the tsconfig-ngc.json for AOT-ready version of this library.

These tests are a work-in-progress, as tests often are.

The src/ folder is divided into

  • app/ - the test "app" and its tests
  • in-mem/ - the source code for the in-memory web api library

A real app would reference the in-memory web api node module; these tests reference the library source files.

The karma-test-shim.js adds the in-mem folder to the list of folders that SystemJS should resolve.

Rollup

The gulp "umd" task runs rollup for tree-shaking.

I don't remember if it ever worked without a lot of warnings. The v0.4.x release updated to [email protected] which required updates to the rollup.config.js.

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.

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.

Ignoring these issues for now.

More Repositories

1

angular

Deliver web apps with confidence 🚀
TypeScript
96,000
star
2

angular.js

AngularJS - HTML enhanced for web apps!
JavaScript
59,091
star
3

angular-cli

CLI tool for Angular
TypeScript
26,756
star
4

components

Component infrastructure and Material Design components for Angular
TypeScript
24,333
star
5

material

Material design for AngularJS
JavaScript
16,637
star
6

angular-seed

Seed project for angular apps.
JavaScript
13,027
star
7

protractor

E2E test framework for Angular apps
JavaScript
8,780
star
8

angularfire

Angular + Firebase = ❤️
TypeScript
7,692
star
9

flex-layout

Provides HTML UI layout for Angular applications; using Flexbox and a Responsive API
TypeScript
5,904
star
10

universal

Server-side rendering and Prerendering for Angular
TypeScript
4,040
star
11

zone.js

Implements Zones for JavaScript
TypeScript
3,243
star
12

quickstart

Angular QuickStart - source from the documentation
JavaScript
3,128
star
13

angular-phonecat

Tutorial on building an angular application.
JavaScript
3,128
star
14

batarang

AngularJS WebInspector Extension for Chrome
JavaScript
2,444
star
15

material-start

Starter Repository for AngularJS Material
JavaScript
2,214
star
16

universal-starter

Angular Universal starter kit by @AngularClass
TypeScript
2,028
star
17

mobile-toolkit

Tools for building progressive web apps with Angular
JavaScript
1,344
star
18

angular.io

Website for the Angular project (see github.com/angular/angular for the project repo)
HTML
1,032
star
19

angular2-seed

TypeScript
1,011
star
20

tsickle

Tsickle — TypeScript to Closure Translator
TypeScript
893
star
21

material.angular.io

Docs site for Angular Components
TypeScript
889
star
22

di.js

Dependency Injection Framework for the future generations...
JavaScript
822
star
23

react-native-renderer

Use Angular and React Native to build applications for Android and iOS
TypeScript
789
star
24

vscode-ng-language-service

Angular extension for Visual Studio Code
TypeScript
777
star
25

dgeni

Flexible JavaScript documentation generator used by AngularJS, Protractor and other JS projects
TypeScript
770
star
26

angular-cn

Chinese localization of angular.io
Pug
761
star
27

router

The Angular 1 Component Router
JavaScript
667
star
28

angular-electron

Angular2 + Electron
TypeScript
610
star
29

devkit

549
star
30

bower-material

This repository is used for publishing the AngularJS Material v1.x library
JavaScript
506
star
31

watchtower.js

ES6 Port of Angular.dart change detection code.
JavaScript
410
star
32

preboot

Coordinate transfer of state from server to client view for isomorphic/universal JavaScript web applications
TypeScript
384
star
33

angular-hint

run-time hinting for AngularJS applications
JavaScript
368
star
34

angular-bazel-example

MOVED to the bazel nodejs monorepo 👉
TypeScript
350
star
35

builtwith.angularjs.org

builtwith.angularjs.org
HTML
271
star
36

protractor-accessibility-plugin

Runs a set of accessibility audits
JavaScript
263
star
37

angularjs.org

code for angularjs.org site
JavaScript
260
star
38

angular-update-guide

An interactive guide to updating the version of Angular in your apps
TypeScript
251
star
39

webdriver-manager

A binary manager for E2E testing
TypeScript
225
star
40

bower-angular

Bower package for AngularJS
CSS
224
star
41

angular-ja

repository for Japanese localization of angular.io
TypeScript
212
star
42

ngSocket

WebSocket support for angular
JavaScript
204
star
43

peepcode-tunes

Peepcode's Backbone.js Music Player Reimplemented in AngularJS
JavaScript
204
star
44

clutz

Closure to TypeScript `.d.ts` generator
Java
163
star
45

benchpress

JavaScript
160
star
46

code.angularjs.org

code.angularjs.org
153
star
47

ngcc-validation

Angular Ivy library compatibility validation project
TypeScript
146
star
48

dgeni-packages

A collection of dgeni packages for generating documentation from source code.
JavaScript
143
star
49

bower-angular-route

angular-route bower repo
JavaScript
143
star
50

atscript-playground

A repo to play with AtScript.
JavaScript
141
star
51

bower-angular-animate

Bower package for the AngularJS animation module
JavaScript
137
star
52

protractor-cookbook

Examples for using Protractor in various common scenarios.
TypeScript
130
star
53

diary.js

Flexible logging and profiling library for JavaScript
JavaScript
127
star
54

bower-angular-i18n

internationalization module for AngularJS
JavaScript
125
star
55

ts-minify

A tool to aid minification of Typescript code, using Typescript's type information.
TypeScript
119
star
56

closure-demo

TypeScript
114
star
57

ngMigration-Forum

109
star
58

watScript

The next generation JavaScript language that will kill ALL the frameworks!
101
star
59

material-adaptive

Adaptive template development with Angular Material
JavaScript
101
star
60

bower-angular-sanitize

angular-sanitize bower repo
JavaScript
99
star
61

code-of-conduct

A code of conduct for all Angular projects
99
star
62

clang-format

Node repackaging of the clang-format native binary
Python
97
star
63

tactical

Data access library for Angular
TypeScript
93
star
64

bower-angular-resource

angular-resource bower repo
JavaScript
92
star
65

dashboard.angularjs.org

AngularJS Dashboard
JavaScript
89
star
66

angular-jquery-ui

jQueryUI widgets wrapped as angular widgets
JavaScript
88
star
67

bower-angular-mocks

angular-mocks.js bower repo
JavaScript
87
star
68

bower-angular-cookies

angular-cookies bower repo
JavaScript
85
star
69

issue-zero

TypeScript
82
star
70

bower-angular-touch

JavaScript
79
star
71

templating

Templating engine for Angular 2.0
JavaScript
76
star
72

a

Library for annotating ES5
JavaScript
67
star
73

material-icons

Common resources for material design in AngularJS
66
star
74

vladivostok

TypeScript
65
star
75

dev-infra

Angular Development Infrastructure
JavaScript
65
star
76

bower-angular-messages

JavaScript
63
star
77

angular-component-spec

Specification for reusable AngularJS components
61
star
78

ci.angularjs.org

ci.angularjs.org CI server scripts
Shell
60
star
79

projects

github reference application for Angular 2.0
JavaScript
58
star
80

codelabs

55
star
81

code.material.angularjs.org

Documentation site for AngularJS Material
HTML
50
star
82

material-tools

Tools for AngularJS Material
TypeScript
47
star
83

jasminewd

Adapter for Jasmine-to-WebDriverJS
JavaScript
46
star
84

material-update-tool

Standalone update tool for updating Angular CDK and Material
TypeScript
46
star
85

material-builds

Build snapshots for @angular/material
JavaScript
45
star
86

material2-docs-content

Docs content for @angular/material
HTML
39
star
87

cdk-builds

Angular CDK builds
JavaScript
38
star
88

benchpress-tree

A reference implementation of a benchpress deep-tree benchmark as seen in Angular
JavaScript
37
star
89

router-builds

@angular/router build artifacts
JavaScript
36
star
90

angular-ko

HTML
36
star
91

prophecy

Deferred/Promise for AngularJS 2.0
JavaScript
36
star
92

answers-app

TypeScript
36
star
93

assert

A runtime type assertion library.
JavaScript
35
star
94

ngo

TypeScript
34
star
95

protractor-console-plugin

Checks the browser log after each test for warnings and errors
JavaScript
34
star
96

examples

TypeScript
33
star
97

introduction-to-angular

TypeScript
33
star
98

microsites

Master repository for sites on the angular.io subdomains (universal.angular.io, material.angular.io, etc)
HTML
29
star
99

core-builds

@angular/core build artifacts
JavaScript
29
star
100

ngtools-webpack-builds

Build artifacts for @ngtools/webpack
JavaScript
28
star