Giter VIP home page Giter VIP logo

in-memory-web-api's Introduction

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.

in-memory-web-api's People

Contributors

brandonroberts avatar caeruskaru avatar caroso1222 avatar crisbeto avatar emilio2hd avatar filipesilva avatar foxandxss avatar igorminar avatar lukewood avatar mathieugeissler avatar mortuel avatar neobyteuk avatar nohomey avatar npmcdn-to-unpkg-bot avatar pabreetzio avatar ruipenso avatar steveschmitt avatar suhasdeshpande avatar thelgevold avatar vishal423 avatar wardbell avatar wheelerlaw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

in-memory-web-api's Issues

Provide a reference to InMemoryBackendService on function overrides

If a method of the InMemoryBackendService is overridden, such as get. In the arguments to the function provide a way to to invoke the InMemoryBackendService collectionHandler.

This will allow overridden methods the contain logic whether to return their own Observer<Response> or defer to the InMemoryBackendService.

This is a terrible representation of what I'm suggesting, but hopefully it gets the point across.

Within handleRequest

try {
      if ('commands' === reqInfo.base.toLowerCase()) {
        return this.commands(reqInfo);

      } else if (this.inMemDbService[reqMethodName]) {
          // omitted for brevity 
        return this.inMemDbService[reqMethodName]({ 
                ...interceptorArgs,
                defaultHandler: this.defaultResponseHandler
         });
      } else {
         this.defaultResponseHandler();
      }    

Perhaps there's a better approach. Currently, I do not see a way of intercepting the get and conditionally providing a response.

Not assigning returned API data to `data` property?

There does not seem to be a simple way to override the data property of returned API data. My API doesn't wrap the returned data in a object property in this way.

I could use overrides but that seems more involved than necessary for such a minor change, or is it? Maybe I'm just misunderstanding this.

Need for hitting in-memory-web-api and external endpoints

I need to be able to continue using in-memory-web-api to serve mock data in development, while at the same time hit external endpoints in production without much change except for the urls. ( This is a slight variation of #15 where in-memory-web-api is registered in AppModule itself. )

Basically I need to be able to use 2 services, one which points to the url, 'app/mock_data' and 'api.server.com/mock_data' and swap between these two in development and production.

But currently, I'm not able to do this because I have to comment out the InMemoryWebApiModule.forRoot(MockData) everytime I have to hit an external endpoint and I can't find any way to conditionally load that in the AppModule imports based on the mode.

Now, I have seen that line in the documentation which says "swap in-memory-web-api out when you have a real api", but I don't wanna do that - because I need the front-end developers to be able to go on with their work without the need to setup of a local api.

Imports in Webpack

Using https://github.com/johnpapa/event-view as a guide, I've tried implementing this in my project which uses webpack. However the import statement doesn't work

import {
  InMemoryBackendConfig,
  InMemoryBackendService,
  SEED_DATA
} from 'angular2-in-memory-web-api/core';

Console Output
bootstrap d05bac4…:50 Uncaught ReferenceError: System is not defined

The offending line is https://github.com/angular/in-memory-web-api/blob/master/core.js#L1

The workaround for webpack is just to use the import from 'angular2-in-memory-web-api/src/core'.

It might be worth changing this to be consistent with most other ng2/typescript libraries.

Downloading for use in Ionic 2 - No tsconfig.json, tslint.json, typings.json installed

Hi, I am totally new to Ionic 2 and Angular 2. Wanted to use the in-memory-web-api in my Ionic 2 app but am facing problems.

When I install the package with "npm i angular-in-memory-web-api --save" I see it in the node-modules folder but in the angular-in-memory-web-api folder there is no tsconfig.json, tslint.json and typings.json.

What can/shall I do?

Strange lint warnings about missing C:/github/angular.in-memory-web-api/src//src/index.ts

If I switch to this new in-memory-web-api library, I get a strange lint warning when running "ng test" on my mac:

WARNING in ./~/angular-in-memory-web-api/index.js
Cannot find source file 'C:/github/angular.in-memory-web-api/src//src/index.ts': Error: Can't resolve './C:/github/angular.in-memory-web-api/src//src/index.ts' in '/Users/xxx/mytestproject/node_modules/angular-in-memory-web-api'
 @ ./src/app/shared/services/test.service.spec.ts 6:34-70
 @ ./src \.spec\.ts
 @ ./src/test.ts

The source file that it can not find is "C:/github/angular.in-memory-web-api/src//src/index.ts" and is unrelated to my project and even my platform (I am using Mac - not windows).

Any plan to support pagination?

Currently /api/models returns the whole collection by default, is there any plan to support pagination via something like /api/models?start=100&limit=50, while start and limit can be customized via InMemoryBackendConfig?

InMemoryBackendService class should <T>

IMHO then we can do this do the class:

protected findById(collection: T[], id: number | string): T;
protected genId(collection: T): T;
protected indexOf(collection: T[], id: number): number;
protected parseId(collection: {id: T;}[], id: string): T;
protected removeById(collection: T[], id: number): boolean;

I can make all these changes and send it off in a PR, but writing this issue to see if you'd want/accept that.

Uncaught TypeError: ctorParameters.map is not a function

I followed the example for setting up the in-memory-web-api and I get the following error

reflection_capabilities.js:58 Uncaught TypeError: ctorParameters.map is not a function.

This occurred right after I added the following import line to my app.module.ts

InMemoryWebApiModule.forRoot(InMemoryDataService)

Parse error with URL like 'response.json'

Asking for URL like response.json will cause error. I tracked down this error to a parseUrl
function of InMemoryBackendService. The problem is, that the collectionName gets seen as base, and the collectionName then is empty, and it throws.

I tried to add slash before the URL, but it ends up with same result.

export class InMemoryDataService implements InMemoryDbService {
    createDb() {
        let response= {
            prop: 'string',
            ...
        }
        return {
            'response.json': response
        }
    }
}

how to intercept http invocations from services loaded from lazy/feature modules

I have InMemoryWebApiModule added into AppModule/CoreModule. now it is able to intercept http invocations from services loaded in AppModule/CoreModule but not from services in lazy loaded, feature modules.

AppModule/CoreModule

 InMemoryWebApiModule.forRoot(InMemoryDataService, {
      passThruUnknownUrl: true
 }),

I have SharedModule that I import in multiple other feature modules.
I understand lazy loaded modules will have different dependency injector. But my question is how to share same InMemoryDataService for CoreModule and all feature modules without duplicating code?

would like to have forChild option like in ngx-translate

How to use unknown url with the same collection name?

I have added a passThruUnknownUrl: true config in this way:
InMemoryWebApiModule.forRoot(InMemoryDataService, { passThruUnknownUrl: true })

And chang
private heroesUrl = 'api/heroes';
to
private heroesUrl = 'https://58ac43fef989751200f99333.mockapi.io/v1/heroes/';

But app still loads heroes from in-memory api.

P/s: When I add one more slash before 'heroes' this way:
private heroesUrl = 'https://58ac43fef989751200f99333.mockapi.io/v1//heroes/';
(as a result link have one more level)
App loads heroes from remote API.

Plunker demo (modified last part TourOfHeroes)

Url to get data

Hi!
I want to use in app url's like /api/v1/heroes. How to do this?

Issue Multiple Services usage

imports: [
  ...
  InMemoryWebApiModule.forRoot(Service1), // "app/service1"
  InMemoryWebApiModule.forRoot(Service2) // "app/service2"
]

When in-memory-web-api is used for multiple services like this, only the last service url(not checked with more than 3, so I dunno if "last" is always true) is available. I confirmed it by switching places of service1 and service2.

Support for custom / composite keys and how they map to urls

in-memory-web-api is great but I would like some my control over how urls are translated to instances of a data array. For instance, given a url like this "/app/modules/1/instances/2" I would like in-memory-web-api to map to the shown extract of an array passed to createDb.

Notice that the data effectively has a composite key of moduleId + moduleInstanceId and does not have an id property. All of which is not well supported by in-memory-web-api right now.

[
 { // Module 1, Instance 2 here:
      moduleId: "1",
      moduleInstanceId: "2",
     ... 
  },
 ...
]

doubt

why should i use this in-memory-web-api

Mention import ordering in documentation

Maybe this is basic Angular stuff we should know, but I think it would still be beneficial to add it to the docs. I was banging my head for a day and half trying to figure out why the in-memory backend wasn't being used.

My initial configuration was like

@NgModule({
  imports: [
    InMemoryWebApiModule.forRoot(...),
    CoreModule.forRoot(),    // imports HttpModule
    // Material 2
    MdIconModule.forRoot(),  // also imports HttpModule -> I DIDN'T KNOW!!
})
class AppModule {}

It seems this ordering will cause the last added HttpModule (with the default XHRBackend) to be used instead of the InMemoryBackendService. Changing the order to have the InMemoryWebApiModule last did the trick.

I think it should be mentioned in the docs that we should make sure to place the module last, just in case.

Wrong license in package.json

package.json states

"license": "ISC",

while license file says it is MIT like all other angular packages. Creates errors on automatic license parsers.

[Suggestion] - change rootPath in InMemoryBackendConfigArgs to be array of paths

Use case:

Api is scoped so scope is part of rootPath.

/api/v2/auth/users
/api/v2/auth/oauth

/api/v2/carparts/wheels
/api/v2/carparts/dors
/api/v2/carparts/keys

rootPath = /api/v2/carparts
collections = {wheels, dors, keys}

Web Api is configured on CarPartsModule.

All calls to /api/v2/auth will passTrough if it is configured.

If we have multiple rootPaths we can mock calls outside of current scope - here carparts.

Cons:
it is possible to have same named endpoints(collections) across scopes:

/api/v2/carparts/keys
/api/v2/security/keys

Error after updating to 0.1.12

I got this error after updating to 0.1.12.

Failed to load resource: the server responded with a status of 404 (Not Found)
Error: (SystemJS) XHR error (404 Not Found) loading http://localhost:3000/traceur
    Error: XHR error (404 Not Found) loading http://localhost:3000/traceur
        at XMLHttpRequest.wrapFn [as _onreadystatechange] (http://localhost:3000/node_modules/zone.js/dist/zone.js:698:29)
        at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:265:35)
        at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:154:47)
        at XMLHttpRequest.ZoneTask.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:335:33)
    Error loading http://localhost:3000/traceur
    Unable to load transpiler to transpile http://localhost:3000/node_modules/angular-in-memory-web-api/index.js
    Error loading http://localhost:3000/node_modules/angular-in-memory-web-api/index.js as "angular-in-memory-web-api" from http://localhost:3000/app/app.module.js
        at XMLHttpRequest.wrapFn [as _onreadystatechange] (http://localhost:3000/node_modules/zone.js/dist/zone.js:698:29)
        at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:265:35)
        at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:154:47)
        at XMLHttpRequest.ZoneTask.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:335:33)
    Error loading http://localhost:3000/traceur
    Unable to load transpiler to transpile http://localhost:3000/node_modules/angular-in-memory-web-api/index.js
    Error loading http://localhost:3000/node_modules/angular-in-memory-web-api/index.js as "angular-in-memory-web-api" from http://localhost:3000/app/app.module.js

We also tried it in angular.io quickstart but got the same error.

The application works with the older versions(0.1.9 and 0.1.10) without any errors.

Please let us know if you need something else.

[Feature Request] Support for nested resources

As best I can tell, there's currently no support for nested resources. Nested resources are relatively common in the REST APIs I've used. For example, I might have an API that provides banking account information by exposing the resource endpoints shown below.

https://myservice.com/accounts
https://myservice.com/accounts/1/transactions

The first is a top-level resource that retrieves basic information for all accounts. The second is a nested resource that retrieves transaction details for a specific account. I don't believe there's a way to support this second, nested resource using the in-memory-web-api.

I would be glad to work up a Pull Request if you're interested in adding this feature. I've overridden parseUrl in my app to identify fully qualified collection names for nested resources. For example, parsing a request to the transactions endpoint shown above would result in a collection name of 'accounts/1/transactions'. The hash I return from `createDb' then must contain a collection key of the same name.

Get nested property of a collection

Hi,
If I understand correctly, while using Angular 2 and this great tool I can only ask for a collection and ID on put, right?
It must be app/[COLLECTIONNAME]/ID. What If my real put request only returns an array of strings and I don't have an id in the schema?
For example I have this collection:

myCollection:  
   {
     store: 
           {items: ['item1', 'items2','item3']}
   }

Can it be more flexible?
How can I update items with put by using in-memory-web-api?
The need for id is somewhat limiting IMO.
Thanks.

Error due to reference to types core-js

Hello,

I'm working on the tour of heroes, implementing it with the AngularCLI and the last version of angular (2.1.0) => https://github.com/davinkevin/Angular2-TourOfHeroes.

So, at the part6 of the TourOfHeroes, I install the in-memory-web-api, but after serving the app I am facing the following error :

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/angular-in-memory-web-api/in-memory-backend.service.d.ts:1:0
Cannot find type definition file for 'core-js'.

The line 1 of the file https://github.com/angular/in-memory-web-api/blob/master/in-memory-backend.service.d.ts#L1 try to load the type file for core-js, but it is only a dev dependency, so not present in my project.

If I add this by installing with npm i -D @types/core-js I have a lot more errors, due to conflicts with es2015.core types definition of Typescript.

** NG Live Development Server is running on http://localhost:4200. **
4569ms building modules
34ms sealing
0ms optimizing
0ms basic module optimization
78ms module optimization
1ms advanced module optimization
12ms basic chunk optimization
0ms chunk optimization
3ms advanced chunk optimization
1ms module and chunk tree optimization
127ms module reviving
9ms module order optimization
4ms module id optimization
3ms chunk reviving
0ms chunk order optimization
11ms chunk id optimization
59ms hashing
0ms module assets processing
165ms chunk assets processing
3ms additional chunk assets processing
0ms recording
0ms additional asset processing
1341ms chunk asset optimization
1050ms asset optimization
42ms emitting
Hash: 0f90a2d2ddfcb98dd1e0
Version: webpack 2.1.0-beta.25
Time: 7531ms
           Asset       Size  Chunks             Chunk Names
  main.bundle.js    3.09 MB    0, 2  [emitted]  main
styles.bundle.js    10.7 kB    1, 2  [emitted]  styles
       inline.js    5.53 kB       2  [emitted]  inline
        main.map    3.21 MB    0, 2  [emitted]  main
      styles.map    14.8 kB    1, 2  [emitted]  styles
      inline.map    5.59 kB       2  [emitted]  inline
      index.html  485 bytes          [emitted]

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:21:13
Duplicate identifier 'PropertyKey'.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:85:4
All declarations of 'name' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:145:4
Subsequent variable declarations must have the same type.  Variable '[Symbol.unscopables]' must be of type '{ copyWithin: boolean; entries: boolean; fill: boolean; find: boolean; findIndex: boolean; keys: ...', but here has type 'any'.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:262:4
All declarations of 'flags' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:276:4
All declarations of 'EPSILON' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:311:4
All declarations of 'MAX_SAFE_INTEGER' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:318:4
All declarations of 'MIN_SAFE_INTEGER' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:457:4
Subsequent variable declarations must have the same type.  Variable '[Symbol.toStringTag]' must be of type '"Symbol"', but here has type 'string'.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:457:4
All declarations of '[Symbol.toStringTag]' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:464:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:492:4
All declarations of 'hasInstance' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:498:4
All declarations of 'isConcatSpreadable' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:504:4
All declarations of 'iterator' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:510:4
All declarations of 'match' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:516:4
All declarations of 'replace' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:522:4
All declarations of 'search' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:528:4
All declarations of 'species' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:534:4
All declarations of 'split' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:540:4
All declarations of 'toPrimitive' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:546:4
All declarations of 'toStringTag' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:552:4
All declarations of 'unscopables' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:609:4
Subsequent variable declarations must have the same type.  Variable '[Symbol.toStringTag]' must be of type '"Math"', but here has type 'string'.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:609:4
All declarations of '[Symbol.toStringTag]' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:613:4
Subsequent variable declarations must have the same type.  Variable '[Symbol.toStringTag]' must be of type '"JSON"', but here has type 'string'.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:613:4
All declarations of '[Symbol.toStringTag]' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:628:4
All declarations of 'size' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:634:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:645:4
All declarations of 'size' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:651:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:666:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:680:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:692:4
All declarations of 'value' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/@types/core-js/index.d.ts:804:4
All declarations of 'prototype' must have identical modifiers.

ERROR in [default] /Users/kevin/Workspace/Angular2-TourOfHeroes/node_modules/typescript/lib/lib.es2015.core.d.ts:17:13
Duplicate identifier 'PropertyKey'.
Child html-webpack-plugin for "index.html":
         Asset     Size  Chunks       Chunk Names
    index.html  2.82 kB       0
webpack: bundle is now VALID.

What can we do to suppress this error ?

Thanks ;)

From angular2-in-memory-web-api to angular-in-memory-web-api

I have a angular-cli bootstrapped project. I had angular2-in-memory-web-api, everything was working as expected. Then i decided to upgrade and use the newest version angular-in-memory-web-api but unfortunately i get the following error (basically my api route /api/whatever does not exist)

image

Any suggestions? and any reason why this upgrade is braking?

API Change: More control over request/response shape

Thanks for the library, it's really handy.

I have a few suggestions for the API. Currently you have to use the /app endpoint with the name of the collection, which then responds with { data: yourCollection}. This has meant i've had to change my actual http contracts to just use a mocked api.

What about modifying the API to look something like this?

export class InMemoryStoreService {
  createEndpoints() {
     return [
       { match: 'api/v1/events', responsebody: { events: [ { id: 1, foo: 'bar'}]} }
     ]
  }
}

This would satisfy my initial needs, but eventually it could be expanded to satisfy more complicated scenarios with proper routing, parameters, headers etc.

Not sure if this is beyond the scope of this project, however I think the above suggestion would at least allow users of this library to not drastically modify their http contracts when building an app that will later call a real API.

Thoughts?

[Suggestion] Allow response configuration

An option to change response type would be a nice addition. Example:
The HTTP spec recommends returning 204 on PUT, as you've implemented. But in practice this recommendation is far from ideal, as it requires another GET request in order to access the processed entity. Now, while I'm all for simple and clean, this is too much. Very few implement this by the spec, especially because having the updated entity in the PUT request response won't break anything.

Put doesn't work

HTTP PUT doesn't work, the server returns 400. As designed? Or should I set the url http://hostname/collectionname/id manually?

Unexpected behavior due to bad handling of overridden responseInterceptor

If the InMemoryDbService class has a responseInterceptor function, InMemoryBackendService currently copies that function to its own responseInterceptor variable, and then uses that variable to call the function while processing requests.

This leads to unexpected behavior, because the function gets executed with the this variable set to the InMemoryBackendService instead of the InMemoryDbService (verify by calling console.log(this) from your responseInterceptor). Any code that uses this inside the overridden responseInterceptor to reference other variables or functions in the InMemoryDbService class will fail.

angular2 in-memory-web-api only for a part of an application

I was wondering if is possible to configure angular2 in-memory-web-api only for a part of an application. I want to reach external endpoints for finished components and use in-memory-web-api for components in development stage.

I've tried to do this in the folowing two ways:

1 - Loading the data in the main and changing the XHRBackend in the components that I want to reach in-memory endpoints;

main.ts

bootstrap(AppComponent, [
    ...
    { provide: SEED_DATA, useClass: InMemoryDataService }
]);

inDevelopmentStage.service.ts

@Component({
    providers: [
        { provide: XHRBackend, useClass: InMemoryBackendService }
    ]
})

2 - Loading the data and changing the XHRBackend in the components that I want to reach in-memory endpoints;

inDevelopmentStage.service.ts

@Component({
    providers: [
        { provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
        { provide: SEED_DATA, useClass: InMemoryDataService }      // in-mem server data
    ]
})

Is there any way that I can achieve this goal?

Thanks for your help!

angular-in-memory-web-api/index.js does not export InMemoryWebApiModule

I started new project with current ionic2rc0, get the following error:

Error: Module ./node_modules/angular-in-memory-web-api/index.js does not export InMemoryWebApiModule (imported by ./.tmp/app/app.module.js)

ionic info

Cordova CLI: 6.3.1
Ionic Framework Version: 2.0.0-rc.0
Ionic CLI Version: 2.1.0
Ionic App Lib Version: 2.1.0-beta.1
OS: Distributor ID: LinuxMint Description:  Linux Mint 17.3 Rosa 
Node Version: v6.7.0

npm list -depth=0

├── @ionic/[email protected]
├── @ionic/[email protected]
├── [email protected] extraneous
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

Any ideas? Or is it a specific ionic problem? Thank you!

Map file lookup fails

The output .js files have references to .js.map files that are not being checked into the repo. This is throwing warnings when trying to consume the module.

0 cannot be used as an id

Because several checks in the code use !id as the check, a value of 0 comes back as a falsy value, thus breaking things. It seems to me that an id with value 0 should be valid. I believe there are three locations in code that would be needed to fix this. I happened to run into it with a post and a delete.

As a test, simply set the db to an initial value of:
[
{
"id": 0,
"otherdata": "my value"
},
{
"id": 1,
"otherdata": "my other value"
}
]

Then, try to do a post or delete of the item with id 0.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.