Security News
PyPI’s New Archival Feature Closes a Major Security Gap
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
can-connect
Advanced tools
@page can-connect @group can-connect.behaviors 1 Behaviors @group can-connect.modules 2 Modules @group can-connect.types 3 Data Types @outline 2
can-connect
provides persisted data middleware. Use it to assemble powerful model layers for
any JavaScript framework, not just CanJS. Play with it in a JSBin here.
It currently can:
Load data:
Convert data into special types:
Real time:
Caching strategies:
raw CRUD Methods
.Caching layers:
The following modules glue certain methods together:
raw CRUD Methods
to callbacks.raw CRUD methods
are called.The following modules are useful to CanJS specifically:
The "can-connect" module exports a connect
function that is used to assemble different
behaviors and some options into a connection
. For example, the following uses connect
and
the [can-connect/constructor] and [can-connect/data-url] behaviors to create a todoConnection
connection:
import connect from "can-connect";
import "can-connect/constructor/";
import "can-connect/data/url/";
var todoConnection = connect(
["constructor","data-url"],
{
url: "/services/todos"
});
A connection typically provides the ability to create, read, update, or delete (CRUD) some data source. That data source is usually accessed through the "Instance Interface" methods:
For example, to get all todos from "GET /services/todos", we could write the following:
todoConnection.getList({}).then(function(todos){ ... });
Behaviors, like [can-connect/constructor] and [can-connect/data-url] implement, extend, or require some set of interfaces. For example, data-url implements the "Data Interface" methods, and [can-connect/constructor] implements the "Instance Interface" methods.
The connect
method calls these behaviors in the right order to create a connection. For instance,
the [can-connect/cache-requests] behavior must be applied after the [can-connect/data-url]
connection. This is because [can-connect/cache-requests], overwrites [can-connect/data-url]'s
[connection.getListData] first check a cache for the data. Only if the data is not present,
does it call [can-connect/data-url]'s [connection.getListData]. So even if we write:
connect(['cache-requests','data-url'])
or
connect(['data-url','cache-requests'])
... our connection will be built in the right order!
A connection is just an object with each behavior object on its prototype chain and its options object at the end of the prototype chain.
This section covers how to install can-connect and then the basics of its use.
Use npm to install can-connect
:
> npm install can-connect --save
Then, depending on your module loader, you'll do one of the following:
Import can-connect and its behaviors like:
import connect from "can-connect";
import "can-connect/data/url/"
require
can-connect and its behaviors like:
var connect = require("can-connect");
import("can-connect/data/url/url");
Configure a package to can-connect and its dependency can-set:
require.config({
packages: [{
name: 'can-connect',
location: 'node_modules/can-connect/dist/amd',
main: 'can-connect'
},{
name: 'can-set',
location: 'node_modules/can-connect/node_modules/can-set/dist/amd',
main: 'src/set'
}]
});
Then use define
to load can-connect and its behaviors like:
define(["can-connect","can-connect/data/url/url"], function(connect){
});
To use can-connect
, it's typically best to start out with the most basic
behaviors: [can-connect/data-url] and [can-connect/constructor]. [can-connect/data-url]
connects the "Data Interface" to a restful service. [can-connect/constructor] adds
an "Instance Interface" that can create, read, update and delete (CRUD) typed data
using the lower-level "Data Interface".
By typed
data we mean data that is more than just plain JavaScript objects. For
example, we might to create todo
objects with an isComplete
method:
var Todo = function(props){
Object.assign(this, props);
};
Todo.prototype.isComplete = function(){
return this.status === "complete";
};
And, we might want a special list type with completed
and active
methods:
var TodoList = function(todos){
[].push.apply(this, todos);
};
TodoList.prototype = Object.create(Array.prototype);
TodoList.prototype.completed = function(){
return this.filter(function(todo){
return todo.status === "complete";
});
};
TodoList.prototype.active = function(){
return this.filter(function(todo){
return todo.status !== "complete";
});
};
We can create a connection that connects a restful "/api/todos"
service to Todo
instances and TodoList
lists like:
var todoConnection = connect(["constructor","data-url"],{
url: "/api/todos",
list: function(listData, set){
return new TodoList(listData.data);
},
instance: function(props) {
return new Todo(props);
}
});
And then use that connection to get a TodoList
of Todo
s:
todoConnection.getList({}).then(function(todos){
var todosEl = document.getElementById("todos-list");
todosEl.innerHTML = "<h2>Active</h2>"+
render(todos.active())+
"<h2>Complete</h2>"+
render(todos.completed());
});
var render = function(todos) {
return "<ul>"+todos.map(function(todo){
return "<li>"+todo.name+
"<input type='checkbox' "+
(todo.isComplete() ? "checked" : "")+"/></li>";
}).join("")+"</ul>";
};
The following demo shows the result:
@demo can-connect/docs/demos/basics.html
This connection also lets you create, update, and destroy a Todo instance as follows:
var todo = new Todo({
name: "take out trash"
})
// POSTs to /api/todos name=take out trash
// server returns {id: 5}
todoConnection.save( todo ).then(function(todo){
todo.id //-> 5
todo.name = 'take out garbage'
// PUTs to /api/todos/5 name=take out garbage
// server returns {id: 5, "take out garbage"}
todoConnection.save( todo ).then( function(todo){
// DELETEs to /api/todos/5
// server returns {}
todoConnection.destroy( todo ).then( function(todo){
});
});
});
Whenever connect
creates a connection, it always adds the [connect.base]
behavior. This behavior defines configurable options that are used by almost
every other behavior. For example, if your data uses an _id
property
to uniquely identify todos, you
can specify this with [connect.base.idProp] like:
var todoConnection = connect(["constructor","data-url"],{
url: "/api/todos",
idProp: "_id"
});
Other behaviors list their configurable options in their own docs page.
If configurable options are not enough, you can overwrite any behavior with your own behavior.
For example, the constructor
's [can-connect/constructor.updatedInstance] behavior
sets the instance's properties to match the result of [connection.updateData]. But if
the PUT /api/todos/5 name=take out garbage
request returned {}
, the following would result in
a todo with only an id
property:
var todo = new Todo({id: 5, name: "take out garbage"})
// PUTs to /api/todos/5 name=take out garbage
// server returns {}
todoConnection.save( todo ).then( function(todo){
todo.id //-> 5
todo.name //-> undefined
});
The following overwrites the behavior of updateData
:
var mergeDataBehavior = {
updateData: function(instance, data){
Object.assign(instance, data);
}
}
var todoConnection = connect([
"constructor",
"data-url",
mergeDataBehavior
],{
url: "/api/todos"
});
You can add your own behavior that overwrite all base behaviors by adding it to the end of the behaviors list.
If you are using CanJS, you can either:
can.Map
and can.List
.Using [can-connect/can/map] to create a connection looks like:
var Todo = can.Map.extend({ ... });
Todo.List = can.List.extend({Map: Todo},{});
var todoConnection = connect([
"data-url",
"can/map",
"constructor",
"constructor-store"
],{
Map: Todo,
url: "/todos"
});
When you bind on a Todo
instance or Todo.List
list, they will automatically call
[can.connect/constructor-store.addInstanceReference] and [can.connect/constructor-store.addListReference].
Using [can-connect/can/super-map] to create a connection looks like:
var Todo = can.Map.extend({ ... });
Todo.List = can.List.extend({Map: Todo},{});
var todoConnection = superMap({
Map: Todo,
url: "/todos"
});
Help us create a special ReactJS behavior that integrates a connection with React's observable life-cycle. Read more here.
Help us create a special AngularJS behavior that integrates a connection with Angular's observable life-cycle. Read more here.
Help us create a special BackboneJS behavior that integrates a connection with Backbone's observable life-cycle. Read more here.
Integrating can-connect
with your framework is typically pretty easy. In general,
the pattern involves creating a behavior that integrates with your framework's
observable instances. The [can-connect/can/map]
behavior can serve as a good guide. You'll typically want to implement the following
in your behavior:
.instance
- Creates the appropriate observable object type.
.list
- Creates the appropriate observable array type.
.serializeInstance
- Return a plain object out of the observable object type.
.serializeList
- Return a plain array out of the observable array type.
.createdInstance
- Update an instance with data returned from createData
.
.updatedInstance
- Update an instance with data returned from updateData
.
.destroyedInstance
- Update an instance with data returned from destroyData
.
.updatedList
- Update a list with raw data.
And, in most frameworks you know when a particular observable is being used, typically observed, and when it can be discarded. In those places, you should call:
[can.connect/constructor-store.addInstanceReference] - Call when an instance is being used.
[can.connect/constructor-store.deleteInstanceReference] - Call when an instance is no longer being used.
[can.connect/constructor-store.addListReference] - Call when a list is being used.
[can.connect/constructor-store.deleteListReference] - Called when a list is no longer being used.
The following is a list of the most important interface methods and properties implemented or consumed by the core behaviors.
.id( props | instance ) -> String
- Returns a unique identifier for the instance or raw data.
.idProp -> String="id"
- The name of the unique identifier property.
.listSet(list) -> set
- Returns the set a list represents.
.listSetProp -> String="__listSet"
- The property on a List that contains its set.
Implemented by [connect.base].
The following methods operate on instances and lists.
.getList(set) -> Promise<List>
- retrieve a list of instances.
.getList(set) -> Promise<Instance>
- retrieve a single instance.
.save(instance) -> Promise<Instance>
- creates or updates an instance.
.destroy(instance) -> Promise<Instance>
- destroys an instance.
Implemented by [can-connect/constructor]. Overwritten by [can-connect/constructor/store].
.createdInstance(instance, props)
- An instance is created.
.updatedInstance(instance, props)
- An instance is updated.
.destroyedInstance(instance, props)
- An instance is destroyed.
.updatedList(list, updatedListData, set)
- A list has been updated.
Implemented by [can-connect/constructor]. Overwritten by [data-connect/real-time], [can-connect/constructor/callbacks-once].
.instance(props) -> Instance
- Creates an instance given raw data.
.list({data: Array<Instance>}) -> List
- Creates a list given an array of instances.
.hydrateInstance(props) -> Instance
- Provides an instance given raw data.
.hydrateList({ListData}, set) -> List
- Provides a list given raw data.
.hydratedInstance(instance)
- Called whenever an instance is created in memory.
.hydratedList(list, set)
- Called whenever a list is created in memory.
.serializeInstance(instance) -> Object
- Returns the serialized form of an instance.
.serializeList(list) -> Array<Object>
- Returns the serialized form of a list and its instances.
Implemented by [can-connect/constructor]. Overwritten by [can-connect/constructor/store], [can-connect/fall-through-cache].
The raw-data connection methods.
.getListData(set) -> Promise<ListData>
- Retrieves list data.
.updateListData(listData[, set]) -> Promise<ListData>
- Update a list's data.
.getSets() -> Promise<Array<Set>>
- Returns the sets available to the connection.
.getData(params) -> Promise<Object>
- Retrieves data for a particular item.
.createData(props, cid) -> Promise<props>
- Creates instance data given the serialized form of the data.
A client ID is passed of the
instance that is being created.
.updateData(props) -> Promise<props>
- Updates instance data given the
serialized form of the data.
.destroyData(props) -> Promise<props>
- Destroys an instance given the seralized
form of the data.
.clear() -> Promise
- Clears all data in the connection.
Implemented by [can-connect/data-url], [can-connect/data/localstorage-cache], [can-connect/data/memory-cache]. Overwritten by [can-connect/cache-requests], [can-connect/data/combine-requests], [can-connect/data/inline-cache], [can-connect/fall-through-cache]. Consumed by [can-connect/constructor].
.gotListData(listData, set) -> ListaData
- List data is retrieved.
.gotData( props, params) -> props
- Instance data is retreived.
.createdData( props, params, cid) -> props
- An instance's data is created.
.updatedData( props, params) -> props
- An instance's data is updated.
.destroyedData( props, params) -> props
- An instance's data is destroyed.
Implemented by [can-connect/data/callbacks]. Overwritten by [can-connect/data/callbacks-cache], [can-connect/real-time].
.parseListData(*) -> ListData
- Given the response of getListData, return the right object format.
.parseInstanceData(*) -> props
- Given the response of getData, createData, updateData, and destroyData,
return the right object format.
Implemented by [can-connect/data-parse].
.addInstanceReference(instance)
- Signal that memory-unsafe actions can be performed on the instance.
.deleteInstanceReference(instance)
- Signal that memory-unsafe actions should be removed.
.addListReference(list)
- Signal that memory-unsafe actions can be performed on the list.
.deleteListReference(list)
- Signal that memory-unsafe actions should be removed.
Implemented by [can-connect/constructor/store].
createInstance( props ) -> Promise<instance>
- Inform the connection an instance has been created.
updateInstance( props ) -> Promise<instance>
- Inform the connection an instance has been updated.
destroyInstance( props ) -> Promise<instance>
- Inform the connection an instance has been destroyed.
Implemented by [can-connect/real-time].
To create your own behavior, call connect.behavior
with the name of your behavior and a function that
returns an object that defines the hooks you want to overwrite or provide:
connect.behavior("my-behavior", function(baseBehavior){
return {
// Hooks here
};
})
For example, creating a simple localStorage behavior might look like:
connect.behavior("localstorage", function(baseBehavior){
return {
getData: function(params){
var id = this.id(params);
return new Promise(function(resolve){
var data = localStorage.getItem(baseBehavior.name+"/"+id);
resolve( JSON.parse(data) )
});
},
createData: function(props){
var id = localStorage.getItem(baseBehavior.name+"-ID") || "0";
var nextId = ++JSON.parse( id );
localStorage.setItem(baseBehavior.name+"-ID"), nextId);
var id = this.idProp;
return new Promise(function(resolve){
props[id] = nextId;
localStorage.setItem(baseBehavior.name+"/"+nextId, props);
resolve( props )
});
},
updateData: function(){ ... },
destroyData: function(){ ...}
};
})
FAQs
Data connection middleware and utilities
The npm package can-connect receives a total of 4,492 weekly downloads. As such, can-connect popularity was classified as popular.
We found that can-connect demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 12 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now allows maintainers to archive projects, improving security and helping users make informed decisions about their dependencies.
Research
Security News
Malicious npm package postcss-optimizer delivers BeaverTail malware, targeting developer systems; similarities to past campaigns suggest a North Korean connection.
Security News
CISA's KEV data is now on GitHub, offering easier access, API integration, commit history tracking, and automated updates for security teams and researchers.