{"id":13661010,"url":"https://github.com/angular/in-memory-web-api","last_synced_at":"2025-10-06T11:30:47.566Z","repository":{"id":38714851,"uuid":"57238867","full_name":"angular/in-memory-web-api","owner":"angular","description":"The code for this project has moved to the angular/angular repo. This repo is now archived.","archived":true,"fork":false,"pushed_at":"2020-05-15T05:23:57.000Z","size":1765,"stargazers_count":1179,"open_issues_count":77,"forks_count":230,"subscribers_count":43,"default_branch":"master","last_synced_at":"2025-01-11T05:36:47.451Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angular.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-27T19:02:56.000Z","updated_at":"2024-12-31T11:33:43.000Z","dependencies_parsed_at":"2022-08-02T23:45:46.003Z","dependency_job_id":null,"html_url":"https://github.com/angular/in-memory-web-api","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular%2Fin-memory-web-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular%2Fin-memory-web-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular%2Fin-memory-web-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular%2Fin-memory-web-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angular","download_url":"https://codeload.github.com/angular/in-memory-web-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235049015,"owners_count":18927715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T05:01:28.525Z","updated_at":"2025-10-06T11:30:42.204Z","avatar_url":"https://github.com/angular.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Dependencies"],"sub_categories":["Demo"],"readme":"# Angular in-memory-web-api\n[![Build Status][travis-badge]][travis-badge-url]\n\nAn in-memory web api for Angular demos and tests\nthat emulates CRUD operations over a RESTy API.\n\nIt 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.\n\nSee [Austin McDaniel's article](https://medium.com/@amcdnl/mocking-with-angular-more-than-just-unit-testing-cbb7908c9fcc) \nfor a quick introduction.\n\n### _It used to work and now it doesn't :-(_\n\nPerhaps you installed a new version of this library? Check the \n[CHANGELOG.md](https://github.com/angular/in-memory-web-api/blob/master/CHANGELOG.md) \nfor breaking changes that may have affected your app.\n\nIf that doesn't explain it, create an \n[issue on github](https://github.com/angular/in-memory-web-api/issues),\npreferably with a small repro.\n\n## Use cases\n\n* Demo apps that need to simulate CRUD data persistence operations without a real server.\nYou won't have to build and start a test server.\n\n* Whip up prototypes and proofs of concept.\n\n* Share examples with the community in a web coding environment such as Plunker or CodePen.\nCreate Angular issues and StackOverflow answers supported by live code.\n\n* Simulate operations against data collections that aren't yet implemented on your dev/test server. \nYou can pass requests thru to the dev/test server for collections that are supported.\n\n* Write unit test apps that read and write data.\nAvoid the hassle of intercepting multiple http calls and manufacturing sequences of responses.\nThe in-memory data store resets for each test so there is no cross-test data pollution.\n\n* End-to-end tests. If you can toggle the app into test mode\nusing the in-memory web api, you won't disturb the real database.\nThis can be especially useful for CI (continuous integration) builds.\n\n\n\u003e**LIMITATIONS**\n\u003e\n\u003eThe _in-memory-web-api_ exists primarily to support the \n[Angular documentation](https://angular.io/docs/ts/latest/ \"Angular documentation web site\").\nIt is not supposed to emulate every possible real world web API and is not intended for production use.\n\u003e\n\u003eMost importantly, it is ***always experimental***. \nWe will make breaking changes and we won't feel bad about it \nbecause this is a development tool, not a production product. \nWe do try to tell you about such changes in the `CHANGELOG.md`\nand we fix bugs as fast as we can.\n\n## HTTP request handling\nThis in-memory web api service processes an HTTP request and \nreturns an `Observable` of HTTP `Response` object\nin the manner of a RESTy web api.\nIt natively handles URI patterns in the form `:base/:collectionName/:id?`\n\nExamples:\n```ts\n  // for requests to an `api` base URL that gets heroes from a 'heroes' collection \n  GET api/heroes          // all heroes\n  GET api/heroes/42       // the hero with id=42\n  GET api/heroes?name=^j  // 'j' is a regex; returns heroes whose name starting with 'j' or 'J'\n  GET api/heroes.json/42  // ignores the \".json\"\n```\n\nThe in-memory web api service processes these requests against a \"database\" - a set of named collections - that you define during setup.\n\n## Basic setup\n\n\u003ca id=\"createDb\"\u003e\u003c/a\u003e\n\nCreate an `InMemoryDataService` class that implements `InMemoryDbService`.\n\nAt minimum it must implement `createDb` which \ncreates a \"database\" hash whose keys are collection names\nand whose values are arrays of collection objects to return or update.\nFor example:\n```ts\nimport { InMemoryDbService } from 'angular-in-memory-web-api';\n\nexport class InMemHeroService implements InMemoryDbService {\n  createDb() {\n    let heroes = [\n      { id: 1, name: 'Windstorm' },\n      { id: 2, name: 'Bombasto' },\n      { id: 3, name: 'Magneta' },\n      { id: 4, name: 'Tornado' }\n    ];\n    return {heroes};\n  }\n}\n```\n\n**Notes**\n\n* The in-memory web api library _currently_ assumes that every collection has a primary key called `id`.\n\n* The `createDb` method can be synchronous or asynchronous.\nIt would have to be asynchronous if you initialized your in-memory database service from a JSON file.\nReturn the database _object_, an _observable_ of that object, or a _promise_ of that object. The tests include an example of all three.\n\n* The in-memory web api calls your `InMemoryDbService` data service class's  `createDb` method on two occasions.\n\n  1. when it handles the _first_ HTTP request \n  1. when it receives a `resetdb` [command](#commands).\n\n  In the command case, the service passes in a `RequestInfo` object,\n  enabling the `createDb` logic to adjust its behavior per the client request. See the tests for examples.\n\n### Import the in-memory web api module\n\nRegister your data store service implementation with the `HttpClientInMemoryWebApiModule`\nin your root `AppModule.imports`\ncalling the `forRoot` static method with this service class and an optional configuration object:\n```ts\nimport { HttpClientModule } from '@angular/common/http';\nimport { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';\n\nimport { InMemHeroService } from '../app/hero.service';\n\n@NgModule({\n imports: [\n   HttpClientModule,\n   HttpClientInMemoryWebApiModule.forRoot(InMemHeroService),\n   ...\n ],\n ...\n})\nexport class AppModule { ... }\n```\n\n**_Notes_**\n\n* Always import the `HttpClientInMemoryWebApiModule` _after_ the `HttpClientModule` \nto ensure that the in-memory backend provider supersedes the Angular version.\n\n* You can setup the in-memory web api within a lazy loaded feature module by calling the `.forFeature` method as you would `.forRoot`.\n\n* In production, you want HTTP requests to go to the real server and probably have no need for the _in-memory_ provider.\nCLI-based apps can exclude the provider in production builds like this:\n  ```ts\n  imports: [\n    HttpClientModule,\n    environment.production ?\n      [] : HttpClientInMemoryWebApiModule.forRoot(InMemHeroService)\n    ...\n  ]\n  ```\n\n# Examples\nThe tests (`src/app/*.spec.ts` files) in the \n[github repository](https://github.com/angular/in-memory-web-api/tree/master/src/app) \nare a good place to learn how to setup and use this in-memory web api library.\n\nSee also the example source code in the official Angular.io documentation such as the\n[HttpClient](https://angular.io/guide/http) guide and the\n[Tour of Heroes](https://angular.io/tutorial/toh-pt6). \n\n# Advanced Features\nSome features are not readily apparent in the basic usage described above.\n\n## Configuration arguments\n\nThe `InMemoryBackendConfigArgs` defines a set of options. Add them as the second `forRoot` argument:\n```ts\n  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 500 }),\n```\n\n**Read the `InMemoryBackendConfigArgs` interface to learn about these options**.\n\n\n## Request evaluation order\nThis service can evaluate requests in multiple ways depending upon the configuration.\nHere's how it reasons:\n1. If it looks like a [command](#commands), process as a command\n2. If the [HTTP method is overridden](#method-override), try the override.\n3. If the resource name (after the api base path) matches one of the configured collections, process that\n4. If not but the `Config.passThruUnknownUrl` flag is `true`, try to [pass the request along to a real _XHR_](#passthru).\n5. Return a 404.\n\nSee the `handleRequest` method implementation for details.\n\n## Default delayed response\n\nBy default this service adds a 500ms delay \nto all data requests to simulate round-trip latency.\n\n\u003e[Command requests](#commands) have zero added delay as they concern \nin-memory service configuration and do not emulate real data requests.\n\nYou can change or eliminate the latency by setting a different `delay` value:\n```ts\n  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 0 }),    // no delay\n  InMemoryWebApiModule.forRoot(InMemHeroService, { delay: 1500 }), // 1.5 second delay\n```\n\n## Simple query strings\nPass custom filters as a regex pattern via query string. \nThe query string defines which property and value to match.\n\nFormat: `/app/heroes/?propertyName=regexPattern`\n\nThe following example matches all names start with the letter 'j'  or 'J' in the heroes collection.\n\n`/app/heroes/?name=^j`\n\n\u003eSearch pattern matches are case insensitive by default. \nSet `config.caseSensitiveSearch = true` if needed.\n\n\u003ca id=\"passthru\"\u003e\u003c/a\u003e\n## Pass thru to a live server\n\nIf an existing, running remote server should handle requests for collections \nthat are not in the in-memory database, set `Config.passThruUnknownUrl: true`.\nThen this service will forward unrecognized requests to the remote server\nvia the Angular default `XHR` backend (it depends on whether your using `Http` or `HttpClient`).\n\n\u003ca id=\"commands\"\u003e\u003c/a\u003e\n## Commands\n\nThe client may issue a command request to get configuration state\nfrom the in-memory web api service, reconfigure it, \nor reset the in-memory database.\n\nWhen the last segment of the _api base path_ is \"commands\", the `collectionName` is treated as the _command_.\n\nExample URLs:\n```sh\n  commands/resetdb   // Reset the \"database\" to its original state\n  commands/config    // Get or update this service's config object\n```\n\nUsage:\n```sh\n  http.post('commands/resetdb', undefined);\n  http.get('commands/config');\n  http.post('commands/config', '{\"delay\":1000}');\n```\n\nCommand requests do not simulate real remote data access.\nThey ignore the latency delay and respond as quickly as possible.\n\nThe `resetDb` command\ncalls your `InMemoryDbService` data service's  [`createDb` method](#createDb) with the `RequestInfo` object,\nenabling the `createDb` logic to adjust its behavior per the client request.\n\nIn the following example, the client includes a reset option in the command request body:\n```ts\nhttp\n  // Reset the database collections with the `clear` option\n  .post('commands/resetDb', { clear: true }))\n\n  // when command finishes, get heroes\n  .concatMap(\n    ()=\u003e http.get\u003cData\u003e('api/heroes')\n        .map(data =\u003e data.data as Hero[])\n  )\n\n  // execute the request sequence and \n  // do something with the heroes\n  .subscribe(...)\n```\n\nSee the tests for other examples.\n\n## _parseRequestUrl_\n\nThe `parseRequestUrl` parses the request URL into a `ParsedRequestUrl` object.\n`ParsedRequestUrl` is a public interface whose properties guide the in-memory web api\nas it processes the request.\n\n### Default _parseRequestUrl_\n\nDefault parsing depends upon certain values of `config`: `apiBase`, `host`, and `urlRoot`.\nRead the source code for the complete story.\n\nConfiguring the `apiBase` yields the most interesting changes to `parseRequestUrl` behavior:\n\n* For `apiBase=undefined` and `url='http://localhost/api/customers/42'`\n    ```ts\n    {apiBase: 'api/', collectionName: 'customers', id: '42', ...}\n    ```\n\n*  For `apiBase='some/api/root/'` and `url='http://localhost/some/api/root/customers'`\n    ```ts\n    { apiBase: 'some/api/root/', collectionName: 'customers', id: undefined, ... }\n    ```\n\n*  For `apiBase='/'` and `url='http://localhost/customers'`\n    ```ts\n    { apiBase: '/', collectionName: 'customers', id: undefined, ... }\n    ```\n\n**The actual api base segment values are ignored**. Only the number of segments matters.\nThe following api base strings are considered identical: 'a/b' ~ 'some/api/' ~ `two/segments'\n\nThis means that URLs that work with the in-memory web api may be rejected by the real server.\n\n### Custom _parseRequestUrl_\n\nYou can override the default parser by implementing a `parseRequestUrl` method in your `InMemoryDbService`.\n\nThe service calls your method with two arguments.\n1. `url` - the request URL string\n1. `requestInfoUtils` - utility methods in a `RequestInfoUtilities` object, including the default parser.\nNote that some values have not yet been set as they depend on the outcome of parsing.\n\nYour method must either return a `ParsedRequestUrl` object or `null`|`undefined`,\nin which case the service uses the default parser.\nIn this way you can intercept and parse some URLs and leave the others to the default parser.\n\n## Custom _genId_\n\nCollection items are presumed to have a primary key property called `id`.\n\nYou can specify the `id` while adding a new item. \nThe service will blindly use that `id`; it does not check for uniqueness.\n\nIf you do not specify the `id`, the service generates one via the `genId` method.\n\nYou can override the default id generator with a method called `genId` in your `InMemoryDbService`.\nYour method receives the new item's collection and collection name. \nIt should return the generated id.\nIf your generator returns `null`|`undefined`, the service uses the default generator. \n\n## _responseInterceptor_\n\nYou can change the response returned by the service's default HTTP methods.\nA typical reason to intercept is to add a header that your application is expecting.\n\nTo intercept responses, add a `responseInterceptor` method to your `InMemoryDbService` class. \nThe service calls your interceptor like this:\n```ts\nresponseOptions = this.responseInterceptor(responseOptions, requestInfo);\n```\n\n\u003ca id=\"method-override\"\u003e\u003c/a\u003e\n## HTTP method interceptors\n\nYou may have HTTP requests that the in-memory web api can't handle properly.\n\nYou can override any HTTP method by implementing a method \nof that name in your `InMemoryDbService`.\n\nYour method's name must be the same as the HTTP method name but **all lowercase**.\nThe in-memory web api calls it with a `RequestInfo` object that contains request data and utility methods.\n\nFor example, if you implemented a `get` method, the web api would be called like this:\n`yourInMemDbService[\"get\"](requestInfo)`.\n\nYour custom HTTP method must return either:\n\n* `Observable\u003cResponse\u003e` - you handled the request and the response is available from this\nobservable.  It _should be \"cold\"_.\n\n* `null`/`undefined` - you decided not to intervene, \nperhaps because you wish to intercept only certain paths for the given HTTP method.\nThe service continues with its default processing of the HTTP request.\n\nThe `RequestInfo` is an interface defined in `src/in-mem/interfaces.ts`. \nIts members include:\n```ts\nreq: Request;           // the request object from the client\ncollectionName: string; // calculated from the request url\ncollection: any[];      // the corresponding collection (if found)\nid: any;                // the item `id` (if specified)\nurl: string;            // the url in the request\nutils: RequestInfoUtilities; // helper functions\n```\nThe functions in `utils` can help you analyze the request\nand compose a response.\n\n## In-memory Web Api Examples\n\nThe [github repository](https://github.com/angular/in-memory-web-api/tree/master/src/app)\ndemonstrates library usage with tested examples.\n\nThe `HeroInMemDataService` class (in `src/app/hero-in-mem-data.service.ts`) is a Hero-oriented `InMemoryDbService`\nsuch as you might see in an HTTP sample in the Angular documentation.\n\nThe `HeroInMemDataOverrideService` class (in `src/app/hero-in-mem-data-override.service.ts`)\ndemonstrates a few ways to override methods of the base `HeroInMemDataService`.\n\nThe tests ([see below](#testing)) exercise these examples.\n\n# Build Instructions\n\nFollow these steps for updating the library.\n\n- `gulp bump` - up the package version number.\n\n- update `CHANGELOG.md` to record the change. Call out _breaking changes_.\n\n- update `README.md` if usage or interfaces change.\n\n- consider updating the dependency versions in `package.json`.\n\n- `npm install` the new package(s) if you did.\n\n- `npm list --depth=0` to make sure they really did install!\n\n- `gulp clean` to delete all generated files.\n\n- `npm test` to dev-build and run tests (see [\"Testing\"](#testing) below).\n\n- `gulp build` to build for distribution.\n\n- git add, commit, and push.\n\n- `npm publish`\n\n- Confirm that angular.io docs samples still work\n\n- Add two tags to the release commit in github\n  - the version number\n  - 'latest'\n\n[travis-badge]: https://travis-ci.org/angular/in-memory-web-api.svg?branch=master\n[travis-badge-url]: https://travis-ci.org/angular/in-memory-web-api\n\n## Testing\n\nThe \"app\" for this repo is not a real app.\nIt's an Angular data service (`HeroService`) and a bunch of tests.\n\n\u003eNote that the `tsconfig.json` produces a `commonjs` module.\nThat's what _Angular specs require_.\nBut when building for an app, it should be a `es2015` module,\nas is the `tsconfig-ngc.json` for AOT-ready version of this library.\n\nThese tests are a work-in-progress, as tests often are.\n\nThe `src/` folder is divided into \n- `app/` - the test \"app\" and its tests\n- `in-mem/` - the source code for the in-memory web api library\n\n\u003eA real app would reference the in-memory web api node module;\nthese tests reference the library source files.\n\nThe `karma-test-shim.js` adds the `in-mem` folder to the list of folders that SystemJS should resolve.\n\n## Rollup\n\nThe gulp \"umd\" task runs rollup for tree-shaking.\n\nI don't remember if it ever worked without a lot of warnings.\nThe `v0.4.x` release updated to `rollup@0.49` which required updates to the `rollup.config.js`.\n\nStill 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. \n\nAlso 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.\n\nIgnoring these issues for now.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangular%2Fin-memory-web-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangular%2Fin-memory-web-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangular%2Fin-memory-web-api/lists"}