1.1.2 • Published 9 months ago

mushroomjs v1.1.2

Weekly downloads
3
License
ISC
Repository
-
Last release
9 months ago

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

See Call as prefer role

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 for vn_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 and batchDeleteAsync
1.1.2

9 months ago

1.2.0-alpha.1

12 months ago

1.1.1

1 year ago

1.1.0

1 year ago

1.1.0-alpha.15

1 year ago

1.1.0-alpha.19

1 year ago

1.1.0-alpha.18

1 year ago

1.1.0-alpha.17

1 year ago

1.1.0-alpha.16

1 year ago

1.1.0-alpha.11

1 year ago

1.1.0-alpha.10

2 years ago

1.1.0-alpha.14

1 year ago

1.1.0-alpha.13

1 year ago

1.1.0-alpha.12

1 year ago

1.1.0-alpha.9

2 years ago

1.1.0-alpha.8

2 years ago

1.1.0-alpha.7

2 years ago

1.1.0-alpha.5

3 years ago

1.1.0-alpha.6

3 years ago

1.1.0-alpha.3

3 years ago

1.1.0-alpha.4

3 years ago

1.1.0-alpha.2

3 years ago

1.1.0-alpha.1

3 years ago

1.0.4

3 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago