# mushroomjs

> Mushroom js driver

Latest version **1.2.0** (published 2026-07-19) · ISC license · 0 weekly downloads

## Install

```sh
npm install mushroomjs
pnpm add mushroomjs
yarn add mushroomjs
bun add mushroomjs
```

## Health

**Score 65/100 (B)** — status: active.

Positive: has types; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads; no esm support.

## Facts

| | |
|---|---|
| Version | 1.2.0 |
| Published | 2026-07-19 |
| First published | 2020-01-08 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 157.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | suco2007 |
| Maintainers | suco2007 |
| Keywords | mushroom |

## Links

- npm: https://www.npmjs.com/package/mushroomjs
- npm.io page: https://npm.io/package/mushroomjs

## Recent versions

- 1.2.0 (latest) — 2026-07-19
- 1.2.0-alpha.8 (alpha) — 2026-02-27
- 1.2.0-alpha.7 — 2026-02-27
- 1.2.0-alpha.6 — 2025-12-07
- 1.2.0-alpha.5 — 2025-03-11
- 1.2.0-alpha.4 — 2024-12-23
- 1.2.0-alpha.3 — 2024-08-27
- 1.2.0-alpha.2 — 2024-08-26
- 1.1.2 — 2023-08-11
- 1.2.0-alpha.1 — 2023-05-15
- 1.1.1 — 2023-02-24
- 1.1.0 — 2023-02-01
- 1.1.0-alpha.19 — 2023-02-01
- 1.1.0-alpha.18 — 2023-01-31
- 1.1.0-alpha.17 — 2023-01-30
- … 21 more at https://npm.io/package/mushroomjs/versions

## README

# Install

```bash
npm install mushroomjs
```

or

```bash
yarn add mushroomjs
```

# Import

Simple

```javascript
import mushroom from "mushroomjs";
```

Builder

```javascript
import { Filter, Sort, Project } from 'mushroomjs';
```

Full

```javascript
import mushroom, {
    defineAsyncResource,
    defineAsyncView,
    fireEvent,
    createRestfulAsyncFunction,

    IdType,

    IMushroom,
    Mushroom,

    MushroomRequest,
    MushroomRequestSetting,
    MushroomRestfulRequest,
    MushroomResponse,

    MushroomResourceBase,
    MushroomListResource,
    MushroomFindByIdResource,
    MushroomCreateResource,
    MushroomBatchCreateResource,
    MushroomUpdateResource,
    MushroomBatchUpdateResource,
    MushroomPartialUpdateResource,
    MushroomDeleteResource,
    MushroomBatchDeleteResource,
    MushroomExtensibleResource,

    MushroomError
} from 'mushroomjs';
```

# Define resource

## Defination

Create a typescript defination script. Ex: api.ts

```javascript
import mushroom, {
    defineAsyncResource,

    IMushroom,

    MushroomRequest,
    MushroomRequestSetting,

    MushroomResourceBase,
    MushroomListResource,
    MushroomCountResource,
    MushroomFindByIdResource,
    MushroomCreateResource,
    MushroomBatchCreateResource,
    MushroomUpdateResource,
    MushroomBatchUpdateResource,
    MushroomPartialUpdateResource,
    MushroomDeleteResource,
    MushroomBatchDeleteResource,

    MushroomListResponse,
    MushroomCountResponse
} from "mushroomjs";

interface Foo {
    id?: string,
    x?: number,
    y?: boolean
}

interface FooCustomFunctionRequest extends MushroomRequest {
    params: {
        f1: boolean,
        f2?: string
    },
    body: {
        a: string,
        b?: number
    }
}

interface FooCustomFunctionResult {
    u: string,
    v: number
}

interface FooCustomFunction {
    customFunctionAsync(request: FooCustomFunctionRequest): Promise<MushroomResponse<FooCustomFunctionResult>>
}

interface FooViewSampleParameters {
    param1: string,
    param2?: number;
}

interface FooViewSampleItemResult {
    v1: IdType,
    v2: boolean,
    v3?: number
}

interface FooViewSample {
    views: {
        sampleAsync(viewParams: FooViewSampleParameters, settings?: MushroomRequestSetting): Promise<MushroomResponse<FooViewSampleItemResult[]>>
    }
}

defineAsyncResource<Foo>({
    name: "foo",
    actions: {
        findMany: { 
            clientCache: false, // false means disabled cache
            paging: "limitOffset",
            includeTotal: true
        }, 
        findById: { 
            clientCache: true // false means disabled cache
        },
        createOne: {},
        createMany: {},
        updateOne: {},
        updateMany: {},
        updatePartially: {},
        deleteOne: {},
        deleteMany: {},
        _raw_http_method_customFunction: {}
    },
    views: {
        sample: { clientCache: true }
    }
});

mushroom.$using("your absolute root API URL");

interface MushroomApi extends IMushroom {
    foo: MushroomResourceBase & MushroomListResource<Foo> & MushroomCountResource, & MushroomFindByIdResource<Foo> & MushroomCreateResource<Foo> & MushroomBatchCreateResource<Foo> & MushroomUpdateResource<Foo> & MushroomBatchUpdateResource<Foo> & MushroomPartialUpdateResource<Foo> & MushroomDeleteResource & MushroomBatchDeleteResource & FooCustomFunction & FooViewSample
}

export default mushroom as MushroomApi;
```

## Usage

```javascript
import mushroom from "./api"

async function example() {
    await mushroom.foo.listAsync();
    await mushroom.foo.getAllAsync();
    await mushroom.foo.countAsync();
    await mushroom.foo.findByIdAsync({id: yourId});
    let newId = await mushroom.foo.createAsync(fooInstance);
    let newIds = await mushroom.foo.batchCreateAsync(fooInstances);
    await mushroom.foo.updateAsync(fooInstance);
    await mushroom.foo.batchUpdateAsync(fooInstances);
    await mushroom.foo.partialUpdateAsync(fooInstance);
    await mushroom.foo.deleteAsync(id);
    await mushroom.foo.batchDeleteAsync(ids);
    await muuhroom.foo.customFunction({ params: {f1: true}, body: {a: 10} });
    let result = await mushroom.foo.views.sample({param1: "abc", param2: 1});
}
```

## Customize headers or/and params of common action

```javascript
mushroom.foo.createAsync(fooInstance, {
    extra: {
        headers: {
            // your custom headers
        },
        params: {
            // your custom params
        }
    }
});
```

## [Advanced] Call as prefer role

To specify the role of user, use field `preferRole` of second parameter. Eg:

The current user has 2 roles `Admin` and `User`, api `foo.list` supports both roles and `Admin` is in higher priority, to switch to `User` role, please follow this example:

```javascript
mushroom.foo.listAsync(arg, {
    preferRole: 'User'
});
```

## [Advanced] Raw request body for customized API

In some special APIs, request data is required in other than JSON format. In this case, use `isRawData` to tell mushroomjs. Eg:

```javascript
// Request body in BINARY format
mushroom.foo.specialApiAsync({
    body: file, // File
    settings: {
        isRawData: true,
        extra: {
            headers: {
                'Content-Type': 'image/jpeg' // change to the MIME type of your file or use octet/stream for general case
            }
        }
        
    }
});


// Request body in FORMDATA format
mushroom.foo.specialApiAsync({
    body: formdata, // FormData
    settings: {
        isRawData: true
    }
});
```

## [Advanced] Text response and Blob response

In some special APIs, response data is not in JSON format. In this case, please do not use `response.result`, use `response.resultAsText(): string` or `response.resultAsBlob(): Blob` instead. Ex:

```javascript
const response = await mushroom.foo.specialApiAsync(/*parameters here if any*/);
const text = response.resultAsText();
```

# Define global view

## Global view defination

Create a typescript defination script. Ex: api.ts

```javascript
import mushroom, {
    defineAsyncView,
    IMushroom,
    MushroomRequestSetting
} from "mushroomjs";

interface SampleViewParameters {
    param1: string,
    param2?: number;
}

interface SampleViewItemResult {
    v1: IdType,
    v2: boolean,
    v3?: number
}

interface SampleView {
    sampleAsync(viewParams: SampleViewParameters, settings?: MushroomRequestSetting): Promise<MushroomResponse<SampleViewItemResult[]>>
}

defineAsyncView("sample", { clientCache: true });

mushroom.$using("your absolute root API URL");

interface MushroomApi extends IMushroom {
    $view: SampleView
}

export default mushroom as MushroomApi;
```

## Global view usage

```javascript
import mushroom from "./api"

async function example() {
    let result = await mushroom.$views.sample({
        param1: "abc", 
        param2: 1
    });
}
```

# Event

## Register event handler

```javascript
import mushroom, { MushroomRestfulRequest, MushroomRequest, MushroomError } from "mushroomjs";

mushroom._on("eventName", fnEventHandler);
```

## Remove event handler

```javascript
mushroom._unbindEvent("eventName"); // remove all event handlers of 'eventName' event
mushroom._unbindEvent("eventName", fnEventHandler); // remove specific event handler of 'eventName' event
```

## Reflection

```javascript
mushroom._hasEvent("eventName"); // return true if eventName has handler(s)
```

## Built-in events

### On request begining

```javascript
mushroom._on("beginRequest", (args: BeginMushroomRequestHandlerArguments) => {});
```

### Affter request ended

```javascript
mushroom._on("endRequest", (args: EndMushroomRequestHandlerArguments) => {});
```

### Before sending request

```javascript
mushroom._on("beforeSend", (request: MushroomRestfulRequest, rawRequest: MushroomRequest) => {});
```

### Switch to online state

```javascript
mushroom._on("online", () => {});
```

### Fall to offline state

```javascript
mushroom._on("offline", () => {});
```

# API URL

```javascript
mushroom.$using(rootApiUrl); // set root API URL
let url = mushroom.$using(); // get current root API URL
```

# [Advanced] Settings for each request

## preferRole

See [Call as prefer role](#advanced-call-as-prefer-role)

## override cache settings

To override [global cache age](#setting-global-cache-age), see `Request level` at [Cache age](#cache-age)

## override global request timeout

To override [global request timeout](#setting-global-request-timeout)

```javascript
mushroom.foo.listAsync(arg, {
    timeout: 3000, // timeout after 3000 miliseconds or 3 seconds
});
```

## inject events for each request

```javascript
mushroom.foo.listAsync(arg, {
    beforeSend: (request, rawRequest) => {}
});
```

## abort request

To abort a request, use `AbortController` in setting. Ex:

```javascript
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 500);
try {
    const res = await mushroom.foo.listAsync({}, {
        abortController: abortController
    });
    console.log(res);
}
catch (e) {
    console.error(e);
}
```

Custom methods:

```javascript
const abortController = new AbortController();
setTimeout(() => abortController.abort(), 500);
try {
    const res = await mushroom.foo.barAsync({
        settings: {
            abortController: abortController
        }
    });
    console.log(res);
}
catch (e) {
    console.error(e);
}
```

# Caching

By default, mushroom js driver supports client cache for 2 methods `listAsync` and `findByIdAsync` if `actions.findMany.clientCache == true`, `actions.findById.clientCache == true`

Please see [Defination](#defination) at Define resource.

Mushroom js driver only supports client cache for request which is `GET` method.

## Invalid cache

Clear resource cache

```javascript
mushroom.foo.invalidCache();
```

Clear cache by url

```javascript
mushroom.$cache.invalid(url) // url: string - a RESTful url will be invalid cache
```

Clear cache by pattern

```javascript
mushroom.$cache.invalid(pattern) // pattern: RegEx - a regular expression of RESTful urls will be invalid cache
```

Clear all cache

```javascript
mushroom.$cache.invalid()
```

## Cache age

Global level

```javascript
mushroom.$setting.set("request.cache.age", ms); // set global cache age value (in milisecond)
```

Request level

```javascript
let result1 = await mushroom.foo.listAsync({ }, {
    cacheAge: 5000 // cache in 5 seconds
});

let result2 = await mushroom.foo.findByIdAsync({
    id: "your id"
}, {
    cacheAge: 10000 // cache in 10 seconds
});

let result = await mushroom.foo.customMethodAsync({ }, {
    cacheAge: 15000 // cache in 15 seconds
});
```

# Settings

## Setting global cache age

```javascript
mushroom.$setting.set("request.cache.age", 300000); // default: 5 minutes
```

## Setting global request timeout

```javascript
mushroom.$setting.set("request.timeout", timeout_in_ms); // default: undefined (mean: depending on each browser/system)
```

## Setting common HTTP methods

```javascript
mushroom.$setting.set("request.common_methods", ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]);
```

## Setting flags

### Log generic information

```javascript
mushroom.$setting.set("diagnostic.log_info", true); // default: false
```

### Warning on slow connection

```javascript
mushroom.$setting.set("diagnostic.warning_slow_connection", true); // default: false
```

Slow connection info will be outputed at console.

```javascript
mushroom.$setting.set("diagnostic.slow_connection_milliseconds", 2000); // default: 2 seconds
```

Slow connection if an API was requested that took more than `diagnostic.slow_connection_milliseconds`

### Log request

```javascript
mushroom.$setting.set("diagnostic.log_request", true); // default: false
```

### Log response

```javascript
mushroom.$setting.set("diagnostic.log_response", true); // default: false
```

### Log cache hit

```javascript
mushroom.$setting.set("diagnostic.log_cache_hit", true); // default: false
```

## For NodeJS

Required addition dependency: `node-fetch`

# Custom extension

## Custom extension defination

```javascript
mushroom.$ext = mushroom.$ext || {};
mushroom.$ext.method1Async = ... // see Defination of Custom method above
```

## Custom extension usage

```javascript
await mushroom.$ext.method1Async(1, 2, 3);
```

# Builders

## Filter builder

Usage

```javascript
import { Filter } from 'mushroomjs';

let filter : IBuilder;

// create filter here

mushroom.foo.listAsync({
    filters: filter.build()
})
```

### eq

```javascript
filter = Filter.eq("x", 10); // x=10
```

### ne

```javascript
filter = Filter.ne("x", 10); // x!=10
```

### lt

```javascript
filter = Filter.lt("x", 10); // x<10
```

### lte

```javascript
filter = Filter.lte("x", 10); // x<=10
```

### gt

```javascript
filter = Filter.gt("x", 10); // x>10
```

### gte

```javascript
filter = Filter.gte("x", 10); // x>=10
```

### min

Alias of `gte`

```javascript
filter = Filter.min("x", 10); // x>=10
```

### max

Alias of `lte`

```javascript
filter = Filter.max("x", 10); // x<=10
```

### in

```javascript
filter = Filter.in("x", [1, 2, 3]); // x:in:1,2,3
```

### nin

```javascript
filter = Filter.nin("x", [1, 2, 3]); // x:nin:1,2,3
```

### all

```javascript
filter = Filter.all("x", [1, 2, 3]); // x:all:1,2,3
```

### like

```javascript
filter = Filter.like("x", "%abc%"); // x:like:%abc%   (% will be url-encoded to %25)
```

### regex

Without options

```javascript
filter = Filter.regex("x", /ab[cd]/); // x:regex:ab[cd]
filter = Filter.regex("x", "ab[cd]"); // x:regex:ab[cd]
```

With options

```javascript
filter = Filter.regex("x", /ab[cd]/i); // x:regex_i:ab[cd]
filter = Filter.regex("x", "ab[cd]", "i"); // x:regex_i:ab[cd]

filter = Filter.regex("x", /ab[cd]/m); // x:regex_m:ab[cd]
filter = Filter.regex("x", "ab[cd]", "m"); // x:regex_m:ab[cd]

filter = Filter.regex("x", /ab[cd]/im); // x:regex_im:ab[cd]
filter = Filter.regex("x", "ab[cd]", "im"); // x:regex_im:ab[cd]
```

### elementMatch

```javascript
filter = Filter.elementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:elemMatch:y=10,z>3
```

### nelementMatch

```javascript
filter = Filter.nelementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:nelemMatch:y=10,z>3
```

### size

```javascript
filter = Filter.size("x", 4); // x:size:4
```

### isNull

```javascript
filter = Filter.isNull("x"); // x:is_null:true
filter = Filter.isNull("x", false); // x:is_null:false
```

### and

```javascript
filter = Filter.and([Filter.eq("y", 10),  Filter.gt("z", 3)]); // y=10&z>3
filter = Filter.and(Filter.eq("y", 10),  Filter.gt("z", 3)); // y=10&z>3
```

### or

```javascript
filter = Filter.or([Filter.eq("y", 10),  Filter.gt("z", 3)]); // y=10|z>3
filter = Filter.or(Filter.eq("y", 10),  Filter.gt("z", 3)); // y=10|z>3
```

### empty

```javascript
filter = Filter.empty(); // empty string
```

### filter chain

```javascript
filter = Filter.eq("a", 1).lt("b", 2); // a=1&b<2
filter = Filter.eq("a", 1).lt("b", 2).or(Filter.eq("c", 3).gte("d", 4)); // :and:a=1,b=2|:and:c=3,d=4
filter = Filter.eq("a", 1).lt("b", 2).and(Filter.or(Filter.eq("c", 3), Filter.gte("d", 4))); // a=1&b=2&c=3|d=4
filter = Filter.empty().eq("a", 1); // a=1
```

### toArray

```javascript
filters = Filter.eq("a", 1).lt("b", 2).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).or("b", 2).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.elementMatch("x", [Filter.eq("a", 1), Filter.lt("b", 2)]).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).toArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
```

### asArray

```javascript
filters = Filter.eq("a", 1).lt("b", 2).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).or("b", 2).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.elementMatch("x", [Filter.eq("a", 1), Filter.lt("b", 2)]).asArray() // [Filter.eq("a", 1), Filter.lt("b", 2)]
filters = Filter.eq("a", 1).asArray() // Error
```

### variables

```javascript
filters = Filter.eq("d", Filter.variables.now()) // d=$$now
filters = Filter.eq("d", Filter.variables.today()) // d=$$today
filters = Filter.eq("d", Filter.variables.userId()) // d=$$user_id
filters = Filter.eq("ip", Filter.variables.userIp()) // ip=$$user_ip
filters = Filter.eq("d", Filter.variables.nowAdd(5, 'hour')) // d=$$now+5hours
filters = Filter.eq("d", Filter.variables.todayAdd(2, 'week')) // d=$$today+2weeks
filters = Filter.in("company_id", Filter.variables.fromName<string>('company_id')) // company_id=$$company_id
filters = Filter.in("number", Filter.variables.fromName<number[]>('my_numbers')) // number:in:$$my_numbers
```

## Sort builder

Usage

```javascript
import { Sort } from 'mushroomjs';

let sort : IBuilder;

// create sort here

mushroom.foo.listAsync({
    sort: sort.build()
})
```

### ascending

```javascript
sort = Sort.ascending("x"); // x
```

### descending

```javascript
sort = Sort.descending("x"); // -x
```

### thenByAscending

```javascript
sort = Sort.ascending("x").thenByAscending("y"); // x,y
```

### thenByDescending

```javascript
sort = Sort.ascending("x").thenByDescending("y"); // x,-y
```

## Project builder

Usage

```javascript
import { Project } from 'mushroomjs';

let project : IBuilder;

// create project here

mushroom.foo.listAsync({
    fields: project.build()
})
```

### include

```javascript
project = Project.include("x"); // x

project = Project.include("x", "y"); // x,y
project = Project.include("x").include("y"); // x,y
```

# Release notes

## 1.2.0

New features:

* Add new setting to specify the common HTTP methods (not need to use header X-HTTP-Method-Override): `request.common_methods`
* Add new rest object field in `MushroomRestfulRequest` to customize `fetch`
* Allow to customize request headers and params of common actions (such as findById, list, create...)
* Support raw request data
* Support variables in filter builder

## 1.1.1

Fix bug:

* Get wrong result when using nested `and` filter in FilterBuilder

## 1.1.0

New features:

* Support Typescript
* Support NodeJS
* Support Abort request
* Support softDelete
* Support `preferRole` for request
* Support `channel` for `vn_text`
* Add builders (Filter, Sort, Project)
* Add new settings for log actions, such as `diagnostic.log_info`, `diagnostic.log_cache_hit`
* Add new methods `countAsync`, `getAllAsync` for resource
* Add new methods `resultAsBlob`, `resultAsText` for reponse.

Fix bugs:

* iOS: missing escape url for filter
* Missing headers which were passed in each api call time
* Wrong in some cases when call api `deleteAsync` and `batchDeleteAsync`

---
_Source: https://npm.io/package/mushroomjs · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
