npm package: @simplus/robin
Description: A frontend micro-service handler
Author: Yehudi Hollevoet
Latest version: 1.4.0

# Robin #

A frontend micro-service handler

## Installation

```
npm install --save @simplus/robin
```

## How does it work ?

The goal of this package is to make requests to RESTFull APIs easy, Robin is a very basic and independent library that is not dependent on a UI framework.
It's architecture is inspired from redux in terms of state managmenet.

### Did you say state management ?

Robin makes requests and triggers events during the process in order to give feedback about the status of each request. 
When a request is refreshed it replaces the content of the previous request in a global state.

The way the state is managed can be different for each microservice, but there is a default behaviour that I will describe later.

For now let's start by a quick overview about how to use this library

## Usage

To use robin it need first to be configured. Good practice is to make a file let's call it robins.ts

### robin.ts ###
```typescript
import {Robin, RobinProvider, CollectionRobin} from "@simplus/robin"
import RobinReact from '@simplus/robin-react'
// this variable will contain all our microservices
const robins = {
	// A very simple Api caller
	ms : new Robin(),
	// A collection microservice
	users : new CollectionRobin({
		baseUrl : '/api/users'
	})
}

// provider has methods that can be used for UI frameworks adaptators
let provider = new RobinProvider(robins)

RobinReact.setProvider(provider)

export {robins}
```

Then we can connect a react component to a robin

### MyComponent.tsx ###

```tsx
import * as React from 'react'
import {Status} from '@simplus/robin'
import {connectRobin} from '@simplus/robin-react'
import {robins} from './robins'

const {ms, users} = robins

// We bind the component to the robins we want to use
@connectRobin([ms, users])
class MyComponent extends React.Component<any,any> {

    componentDidMount(){
        // we make a request when the component is mounted
        
        ms.get('call-identifier', '/api/some-call')
        users.find({})
    }

    renderUsers(){
        if(users.isError(users.ACTIONS.find))
            return <div>{users.isError(users.ACTIONS.find)}</div>

        if(users.isLoading(users.ACTIONS.find))
            return <div>Loading users...</div>  
        
        return <div>
            {users.getCollection().map( u => {
                return <div>{u.firstname} {u.lastname}</div>  
            })}
        </div>
    }

    renderResult(){
        if(ms.isError('call-identifier'))
            return <div> {ms.getError('lis-of-users')} </div>
        
        if(ms.isLoading('call-identifier'))
            return <div> loading... </div>

        return <div> {JSON.stringify(ms.getResult('call-identifier'))} </div>
    }

    render(){
        return <div>
            <h1>Users</h1>
            {this.renderUsers()} 
            <h1>Api call</h1>
            {this.renderResult()}
        </div>
    }
}

export {MyComponent}
```

### Queue requests
If you want to handle requests as promises there is a way to do it since v1.3.1. To do so use the when method:

```typescript
MyRobin.when(MyRobin.find({})).then(label => {
    console.log('We received the data:', MyRobin.getResult(label))
}).catch( err => {
    // SHould never enter here if the request failed
    console.log('An error has occured')
})
```

### Cache Requests (from version 1.3.2)
if you want to cache the results of requests in the browser memory (lifetime of the webpage) you can add the parameter when you create the robin

```typescript
const myRobin = new Robin({
    cache : true
})
// if you want to specify the methods (get, post, put)
const myRobin = new Robin({
    cache : {
        methods : ['get', 'post']
    }
})
```

## API

### Robin

#### constructor()
There is one constructor with no arguments to create a simple robin

#### constructor(options)
There is one constructor with options, for the moment options are :

* __namespace__: _string_ : A value that can be overwritten for very specific reasons that require a good knowledge of the library, should not be used unless the develop know what he is doing

#### getError(key: string): any
This method allows you to get the last error for a given key

#### getResult(key: string): any 
This method allows you to get the result for a given key

#### getStatus(key: string): Status
This method allows you to get the status for a given key

#### reducer(): any
This method generates a reducer that is compatible with redux and that will contain all the information about the state. We deprecated the use of reducers directly in react, if possible use the robin-react module that is more adapted to the usage of this library

#### get(key: string, url: string, config?: AxiosRequestConfig, options?: RequestOptions)
This method refreshes a key with a get request
Arguments are:

* __key__: _string_ : the key to wich the request is associated
* __url__: _string_ : the url of the request
* __config__: _AxiosRequestConfig_ : a config for the request see [Axios documentation](https://github.com/axios/axios)
* __options__: _RequestOptions_ : the request options wich are detailled bellow

..* __overwriteAction__ :_(action: Action) => Action_: this allows to overwrite the action generated by the result of the request and is generally used for when you overwrite the behaviour of a robin (see "Create your own robin")

#### delete(key: string, url: string, config?: AxiosRequestConfig, options?: RequestOptions)
This method refreshes a key with a delete request
Arguments are:

* __key__: _string_ : the key to wich the request is associated
* __url__: _string_ : the url of the request
* __config__: _AxiosRequestConfig_ : a config for the request see [Axios documentation](https://github.com/axios/axios)
* __options__: _RequestOptions_ : the request options wich are detailled bellow

..* __overwriteAction__ :_(action: Action) => Action_: this allows to overwrite the action generated by the result of the request and is generally used for when you overwrite the behaviour of a robin (see "Create your own robin")


#### put(key: string, url: string, data?:any, config?: AxiosRequestConfig, options?: RequestOptions)
This method refreshes a key with a put request
Arguments are:

* __key__: _string_ : the key to wich the request is associated
* __url__: _string_ : the url of the request
* __data__: _any_ : the data that need to be send to the server (works the same way as axios)
* __config__: _AxiosRequestConfig_ : a config for the request see [Axios documentation](https://github.com/axios/axios)
* __options__: _RequestOptions_ : the request options wich are detailled bellow

..* __overwriteAction__ :_(action: Action) => Action_: this allows to overwrite the action generated by the result of the request and is generally used for when you overwrite the behaviour of a robin (see "Create your own robin")

#### post(key: string, url: string, data?:any, config?: AxiosRequestConfig, options?: RequestOptions)
This method refreshes a key with a post request
Arguments are:

* __key__: _string_ : the key to wich the request is associated
* __url__: _string_ : the url of the request
* __data__: _any_ : the data that need to be send to the server (works the same way as axios)
* __config__: _AxiosRequestConfig_ : a config for the request see [Axios documentation](https://github.com/axios/axios)
* __options__: _RequestOptions_ : the request options wich are detailled bellow

..* __overwriteAction__ :_(action: Action) => Action_: this allows to overwrite the action generated by the result of the request and is generally used for when you overwrite the behaviour of a robin (see "Create your own robin")

#### set (key: string, data: any, url: string= '__localMemory',  options?: Partial <RequestOptions & {method: 'get'|'post'|'put'|'delete'}>)
This method stores the data in a cache against a key
Arguments are:

* __key__: _string_ : the key to which the data is associated
* __data__: _any_ : the data that need to be stored
* __url__: _string_ : the url of the request if any
* __options__: _RequestOptions_ : the request options


## Overwrite Requests
if you want to overwrite your requests there is a way to do so from version (1.3.14)

#### get (key: string, url: string, data: any, options?: RequestOptions)

* __key__: _string_ : the key to which the data is associated
* __url__: _string_ : the url of the request if any
* __data__: _any_ : the data that need to be stored
* __options__: _RequestOptions_ : the request options
```typescript
const overwrite = MyRobin.overwriteResult()
overwrite.get('label', '/some-url', data)
```

#### post (key: string, url: string, data?: any, options?: RequestOptions)

* __key__: _string_ : the key to which the data is associated
* __url__: _string_ : the url of the request if any
* __data__: _any_ : the data that need to be stored
* __options__: _RequestOptions_ : the request options
```typescript
const overwrite = MyRobin.overwriteResult()
overwrite.post('label', '/some-url', data)
```

#### put (key: string, url: string, data?: any, options?: RequestOptions)

* __key__: _string_ : the key to which the data is associated
* __url__: _string_ : the url of the request if any
* __data__: _any_ : the data that need to be stored
* __options__: _RequestOptions_ : the request options
```typescript
const overwrite = MyRobin.overwriteResult()
overwrite.put('label', '/some-url', data)
```

## Overwrite Collection Requests
if you want to overwrite your robin collection requests there is a way to do so from version (1.3.14)

#### create(model: Model)

* __model__: _Model_ : the updated data
```typescript
const overwrite = MyRobin.overwriteCollectionResult()
overwrite.create(data)
```

#### update(id: string, model: Model)

* __id__: _string_ : the key to which the data is associated
* __model__: _Model_ : the updated data
```typescript
const overwrite = MyRobin.overwriteCollectionResult()
overwrite.update('key', data)
```

#### remove(id: string, model: Model)

* __id__: _string_ : the key to which the data is associated
* __model__: _Model_ : the updated data
```typescript
const overwrite = MyRobin.overwriteCollectionResult()
overwrite.remove('key', data)
```

#### findOne(id: string, model: Model)

* __id__: _string_ : the key to which the data is associated
* __model__: _Model_ : the updated data
```typescript
const overwrite = MyRobin.overwriteCollectionResult()
overwrite.findOne('key', data)
```

#### find(data?: Object|null)

* __data__: _Object|null_ : the updated data
```typescript
const overwrite = MyRobin.overwriteCollectionResult()
overwrite.find(data)
```