1.0.28 • Published 2 years ago

forked.sirius.adapter v1.0.28

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

sirius.adapter

sirius.adapter is a module to connect to a sirius.js/sirius.ts-crafted backend. It automatically detects and provide a model representation to each models in the backend that can be used to manipulate the corresponding model. Making it a real-life ORM for the frontend.

sirius-connect also provide the ability to manage auth & session under-the-hood.

Table of Contents

  1. Installation
  2. Testing
  3. Concepts
  4. Usage
  5. Using with another backend

Installation

Using npm

npm install forked.sirius.adapter --save

Using yarn

yarn add forked.sirius.adapter

Browser

You can use unpkg CDN to get sirius.adapter bundled script, and put it in your script tag.

Testing

All tests suits & mock can be found in the ./tests folder.

to run the tests simply run this command

npm test

Concepts

The two main concept in this module are ModelFactory and ModelInstance.

A ModelFactory is an object that represents a table in the database. It can be use to create & fetch the Instance

While ModelInstance is an object that represents a row of a table in the database. It can be use to manipulate the corresponding row.

Usage

NOTICE : READ THE CONCEPTS BEFORE PROCEEDING!

Initialization

First make an instance of a SiriusAdapter from a SiriusAdapter class.

new SiriusAdapter(backendURL: string, port?: number)

Example

import SiriusAdapter from 'forked.sirius.adapter';

const adapter = new SiriusAdapter('localhost', 1234);
// or
const adapter = new SiriusAdapter('192.168.1.3', 1234);
// or
const adapter = new SiriusAdapter('https://sirius-backend.url', 80);

Connecting to backend

Now that you've created an adapter instance, you can use that object to connect to the backend using the provided information before.

Invoke .connect() on the adapter. This method will return a promise that resolves to an object containing ModelFactory on each key (singular-capitalized table name), depending on your backend.

Signature

adapter.connect(): Promise<{[key: string]: ModelFactory}>

Example

adapter.connect().then((factories) => {
	// `factories` will contain an object that has it keys depending on the specified backend.
	// each key will contain a corresponding ModelFactory for that model

	factories = {
		User: ModelFactory,
		Token: ModelFactory,
		//...the rest of the models defined in the backend
	};
});

You might want to store this factories object into a state or pass to different module that will use that.

Fetching instances

Using the factories that we've got from the previous .connect() method's promise, we can pull the Instance (data) for a specific model.

We can either get a set of data (collection) or a single one.

Collection

To get a collection of say, User Instance, invoke the .collection() method on the User Factory stored in the factories object.

Signature :

factories[modelName]collection(): Promise<{count: number; rows: ModelInstance[]}>

Example :

// after .connect() and resolve a factories object :

factories.User.collection().then((result) => {
    // result will contain an object with `count` and `rows` property
    // `count` will contain the number of rows found in the database
    // while `rows` will contain an array of ModelInstance

    result = {
        count: number,
        rows: ModelInstance[]
    }
});

Single

To get a single User Instance, invoke the .single() method on the User Factory stored in the factories object.

Signature :

factories[modelName]single(id: number): Promise<ModelInstance>;

Example :

factories.User.single(1).then((user) => {
	// `user` will contain a data of the user with the corresponding id provided in the .single() method
	// `user` also contain methods that can directly manipulate the corresponding user
	user = {
		id: number,
		save: () => ModelInstance,
		update: () => ModelInstance,
		delete: () => ModelInstance,
		// other user fields defined in the backend
	};
});

Creating a new instance

Creating a new instance is pretty simple, take the factories object again, and using the model we prefer, we can simply call .create() and pass the desired data as a parameter.

Signature :

factories[modelName]create(data: any): Promise<ModelInstance>

Example :

factories.User.create({
	name: 'Lorem Ipsum',
	username: 'lorem.ipsum.21',
	password: 'secret',
	// other fields
}).then((user) => {
	// the `user` will contain a ModelInstance corresponds to the newly created user with the provided data
	user = {
		id: number,
		name: string,
		username: string,
		password: string,
		// other fields
	};
});

Manipulating instances

We can update and delete an instance directly using the instance object.

user.update(data: any): Promise<ModelInstance>;
user.delete(): Promise<ModelInstance>;

since the methods are called on the instance itself, it automatically knows the id of the instance and use that to tell the backend which row to manipulate.

Options

You can define how the response will structured with the options object

Signature:

options: {
	limit?: number;
	offset?: number;
	attributes?: string[];
	include?: ICollectionIncludeOptions[];
	order?: string[] | string[][];
}

Authorization

Some of the action (fetching instances, creating a new instance, update & delete an instance) maybe requiring a client to be authorized. In order to do that, you need to authenticate before any action. You only do this once, and if its success, you can confidently proceed to your 'authentication-required' action.

First, you need to create an AuthProvider instance. To do that, just invoke the .getAuthProvider() methods on the adapter object.

Signature:

adapter.getAuthProvider(): AuthProvider

Example :

const authProvider = adapter.getAuthProvider();

Authenticate

To do an authentication, simply invoke the .set() method on the authProvider and pass the authentication data as a parameter. Remember, the data that you provide are depends on how your backend's login logic works.

Signature :

authProvider.set(data: any): Promise<ModelInstance>

Example :

authProvider.set({ username: 'lorem.ipsum.21', password: 'secret' })
    .then((loggedInUser) => {
        // loggedInUser will contain a ModelInstance corresponds to the matching user in the database
    }).catch((err) => {
        // error happens when the provided data is not matching with any rows in the database
    });

the .set() method will return a promise that resolves to a ModelInstance corresponds to a User found with the matching credentials or throw an error otherwise.

Get user data

After an authentication, a token & a refreshToken is generated. This two value is stored in the localStorage and used as a headers to each request so that the backend knows our client has been authenticated.

To get the User data, invoke .get() on the authProvider object.

Signature :

authProvider.get(): Promise<ModelInstance>

Example :

authProvider.get().then((loggedInUser) => {
    // loggedInUser will contain a ModelInstance that corresponds to a logged in user
}).catch((err) => {
    // no authentication has been invoked
});

Remove the authentication data

This could be done by invoking the .remove() methods on the authProvider object. This method's promise is always resolves.

Signature :

authProvider.remove(): Promise<any>

Example :

authProvider.remove().then(() => {
    // you are no longer to do the authentication-needed actions
});

Error Handling

You can always catch every single methods on the ModelFactory,ModelInstance and AuthProvider and get a clear structured message on how the errors happens.

Using with another backend

sirius.adapter can be used with another backend as long as the backend use the REST API endpoints concepts as wrote in this article.

REST API best practices

1.0.28

2 years ago

1.0.27

2 years ago

1.0.26

2 years ago

1.0.25

2 years ago