Easily create fluent interfaces
$ yarn add schematic-fluent
Example with fetch wrapper
import fluent from "schematic-fluent"
// Declare instance creator
const createFetch = fluent({
methods: {
from: () => url => ({ url: `/${url}` }),
get: () => url => ({ method: "GET", url }),
post: () => url => ({ method: "POST", url }),
put: () => url => ({ method: "PUT", url }),
delete: () => url => ({ method: "DELETE", url }),
paginate: () => (page, limit) => ({ page, limit })
},
executors: {
getOne: ({ url, method }) => id => fetch(`${url}/${id}`, { method: "GET" }),
getAll: ({ url, page, limit }) => () =>
fetch(`${url}?page=${page}&limit=${limit}`),
execute: ({ url, method }) => body => fetch(url, { method, body })
},
defaults: () => ({
page: 1,
limit: 10
})
})
// Usage:
createFetch()
.getOne(1)
.then(console.log)
createFetch()
.from("photos")
.page(1, 10)
.getAll()
.then(console.log)
createFetch()
.post("photos")
.execute(form)
.then(console.log)
There are 4 parameters:
Method is a function that accepts params and returns object that will be merged with context.
It adds fluent method to the instance (accepts options and returns the instance)
Same as methods but doesn't accept arguments
Executor is a function that accepts params and returns something.
It adds method to the instance that will return executor result
Function that declares default context
Returns a shallow clone of context
createFetch()
.post("photos")
.getContext() // => { url: '/photos', method: 'POST' }
Clones current fluent interface
const a = createFetch().post("photos")
const b = a.clone()
b.post("blog")
b.getContext()
// => { url: '/blog', method: 'POST' }
a.getContext()
// => { url: '/photos', method: 'POST' }
You can extend fluent instances with new flags/methods/executors.
const something = fluent({
methods: {
foo: () => foo => ({ foo })
}
})
const instance = something().foo("bar")
const withBaz = instance.extend({
methods: {
baz: () => baz => ({ baz })
}
})
instance.baz("lol")
instance.getContext() // => { foo: 'bar', baz: 'lol' }
Like previous .extend()
but without initialized instance:
const something = fluent({
methods: {
foo: () => foo => ({ foo })
}
})
const withBaz = something.extend({
methods: {
baz: () => baz => ({ baz })
}
})
withBaz()
.foo("bar")
.baz("lol")
.getContext() // => { foo: 'bar', baz: 'lol' }
You can add immutable: true
for schema.
With this flag, each method called will clone fluent instance:
const createFoo = fluent({
immutable: true,
methods: {
foo: () => foo => ({ foo })
}
})
const Root = createFoo()
const Bar = root.foo("bar")
Root.getContext() // => {}
Bar.getContext() // { foo: 'bar' }
You can add shortcuts for existed methods by calling methods from 2nd argument
2nd argument has flag
and method
callbacks which call choosed method with options
fluent({
methods: {
foo: () => foo => ({ foo })
},
flags: {
withBar: ({ foo }, { method }) => method("foo", foo + "bar")
}
})