mushroomjs v1.1.2
Install
npm install mushroomjs
or
yarn add mushroomjs
Import
Simple
import mushroom from "mushroomjs";
Builder
import { Filter, Sort, Project } from 'mushroomjs';
Full
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
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
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});
}
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:
mushroom.foo.listAsync(arg, {
preferRole: 'User'
});
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:
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
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
import mushroom from "./api"
async function example() {
let result = await mushroom.$views.sample({
param1: "abc",
param2: 1
});
}
Event
Register event handler
import mushroom, { MushroomRestfulRequest, MushroomRequest, MushroomError } from "mushroomjs";
mushroom._on("eventName", fnEventHandler);
Remove event handler
mushroom._unbindEvent("eventName"); // remove all event handlers of 'eventName' event
mushroom._unbindEvent("eventName", fnEventHandler); // remove specific event handler of 'eventName' event
Reflection
mushroom._hasEvent("eventName"); // return true if eventName has handler(s)
Built-in events
On request begining
mushroom._on("beginRequest", (args: {request: MushroomRestfulRequest}) => {});
Affter request ended
mushroom._on("endRequest", (args: {request: MushroomRestfulRequest, response?: any, error?: MushroomError, cache?: unknown}) => {});
Before sending request
mushroom._on("beforeSend", (request: MushroomRestfulRequest, rawRequest: MushroomRequest) => {});
Switch to online state
mushroom._on("online", () => {});
Fall to offline state
mushroom._on("offline", () => {});
API URL
mushroom.$using(rootApiUrl); // set root API URL
let url = mushroom.$using(); // get current root API URL
Advanced Settings for each request
preferRole
override cache settings
To override global cache age, see Request level
at Cache age
override global request timeout
To override global request timeout
mushroom.foo.listAsync(arg, {
timeout: 3000, // timeout after 3000 miliseconds or 3 seconds
});
inject events for each request
mushroom.foo.listAsync(arg, {
beforeSend: (request, rawRequest) => {}
});
abort request
To abort a request, use AbortController
in setting. Ex:
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:
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 at Define resource.
Mushroom js driver only supports client cache for request which is GET
method.
Invalid cache
Clear resource cache
mushroom.foo.invalidCache();
Clear cache by url
mushroom.$cache.invalid(url) // url: string - a RESTful url will be invalid cache
Clear cache by pattern
mushroom.$cache.invalid(pattern) // pattern: RegEx - a regular expression of RESTful urls will be invalid cache
Clear all cache
mushroom.$cache.invalid()
Cache age
Global level
mushroom.$setting.set("request.cache.age", ms); // set global cache age value (in milisecond)
Request level
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
mushroom.$setting.set("request.cache.age", 300000); // default: 5 minutes
Setting global request timeout
mushroom.$setting.set("request.timeout", timeout_in_ms); // default: undefined (mean: depending on each browser/system)
Setting flags
Log generic information
mushroom.$setting.set("diagnostic.log_info", true); // default: false
Warning on slow connection
mushroom.$setting.set("diagnostic.warning_slow_connection", true); // default: false
Slow connection info will be outputed at console.
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
mushroom.$setting.set("diagnostic.log_request", true); // default: false
Log response
mushroom.$setting.set("diagnostic.log_response", true); // default: false
Log cache hit
mushroom.$setting.set("diagnostic.log_cache_hit", true); // default: false
For NodeJS
Required addition dependency: node-fetch
Custom extension
Custom extension defination
mushroom.$ext = mushroom.$ext || {};
mushroom.$ext.method1Async = ... // see Defination of Custom method above
Custom extension usage
await mushroom.$ext.method1Async(1, 2, 3);
Builders
Filter builder
Usage
import { Filter } from 'mushroomjs';
let filter : IBuilder;
// create filter here
mushroom.foo.listAsync({
filters: filter.build()
})
eq
filter = Filter.eq("x", 10); // x=10
ne
filter = Filter.ne("x", 10); // x!=10
lt
filter = Filter.lt("x", 10); // x<10
lte
filter = Filter.lte("x", 10); // x<=10
gt
filter = Filter.gt("x", 10); // x>10
gte
filter = Filter.gte("x", 10); // x>=10
min
Alias of gte
filter = Filter.min("x", 10); // x>=10
max
Alias of lte
filter = Filter.max("x", 10); // x<=10
in
filter = Filter.in("x", [1, 2, 3]); // x:in:1,2,3
nin
filter = Filter.nin("x", [1, 2, 3]); // x:nin:1,2,3
all
filter = Filter.all("x", [1, 2, 3]); // x:all:1,2,3
like
filter = Filter.like("x", "%abc%"); // x:like:%abc% (% will be url-encoded to %25)
regex
Without options
filter = Filter.regex("x", /ab[cd]/); // x:regex:ab[cd]
filter = Filter.regex("x", "ab[cd]"); // x:regex:ab[cd]
With options
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
filter = Filter.elementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:elemMatch:y=10,z>3
nelementMatch
filter = Filter.nelementMatch("x", [Filter.eq("y", 10), Filter.gt("z", 3)]); // x:nelemMatch:y=10,z>3
size
filter = Filter.size("x", 4); // x:size:4
isNull
filter = Filter.isNull("x"); // x:is_null:true
filter = Filter.isNull("x", false); // x:is_null:false
and
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
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
filter = Filter.empty(); // empty string
filter chain
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
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
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
Sort builder
Usage
import { Sort } from 'mushroomjs';
let sort : IBuilder;
// create sort here
mushroom.foo.listAsync({
sort: sort.build()
})
ascending
sort = Sort.ascending("x"); // x
descending
sort = Sort.descending("x"); // -x
thenByAscending
sort = Sort.ascending("x").thenByAscending("y"); // x,y
thenByDescending
sort = Sort.ascending("x").thenByDescending("y"); // x,-y
Project builder
Usage
import { Project } from 'mushroomjs';
let project : IBuilder;
// create project here
mushroom.foo.listAsync({
fields: project.build()
})
include
project = Project.include("x"); // x
project = Project.include("x", "y"); // x,y
project = Project.include("x").include("y"); // x,y
Release notes
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
forvn_text
- Add builders (Filter, Sort, Project)
- And 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
andbatchDeleteAsync
9 months ago
12 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago