# Protocaller
NPM Lib that wraps rxjs for calling request through axios and soap

## Getting started 🚀

The directory is as follows:

    .
    └── src                                     ##MAIN CONTENT
    |    ├── __tests__         
    |    ├── config            
    |    ├── errors            
    |    ├── interfaces        
    |    ├── lib               
    |    ├── rest              
    |    ├── soap  # Part of example server
    |    ├── test
    |    ├── base-request.ts
    |    ├── caller-factory.ts
    |    ├── enums.ts
    |    ├── notifier.ts
    |    └── index.ts
    ├── package.json
    ├── tsconfig.json
    ├── tslint.json
    └── README.md

As you may see, the lib is locate at the src directory


### Pre-requisites 📋

Be familiarized with RXJS lib for better understanding about the behavior of this lib

## Installing

Using npm:

```bash
$ npm install @compara/protocaller
```

Using yarn:

```bash
$ yarn add @compara/protocaller
```

## Examples

### Rest Calls

To make rest request you will need to build a rest client, to do that, you have three **possible** options, 
**Providing attributes step by step (Declarative approach)**, **Providing an entire config** and a 
**mixture between Declarative approach and Config option**:

#### Providing attributes step by step (Declarative approach):


*  Using an Oauth Credentials type

```typescript
  import {
    CredentialsType,
    OauthConfig,
    RequestData,
    RestClientBuilder,
    RestServiceConfig
  } from "@comparaonline/protocaller"

  const OAuthConf = <OauthConfig>{
    "type": 'oauth',
    "realm": "some_realm", // this field is optional.
    "consumer": {
      "key": "some_key",
      "secret": "some_secret"
    },
    "token": {
      "key": "some_key_again",
      "secret": "some_secret_again"
    },
    signature_method: 'HMAC-SHA1' // this field is optional. 'HMAC-SHA1' is the default value 
  }
  const restClientBuilder = new RestClientBuilder()
  const reqData = <RequestData>{
    httpMethod: 'GET'
  }
  

  try {
    const client = restClientBuilder.
    setCredentials(CredentialsType.OAUTH, oAuthConf).
    setUrl('http://localhost:8080/test').
    setRetryOptions({
      retryAttempts: 3,
      exponentialDelay: 2
    }).
    build();
  
    const result = await client.call(reqData).toPromise()
    //DO SOMETHING...
  } catch (e) {
    //DO SOMETHING...
  }

```

* Using JWT Credentials type

```typescript
  import {
  CredentialsType,
  RequestData,
  RestClientBuilder,
  RestServiceConfig
} from "@comparaonline/protocaller"
import {JWTConfig} from "./jwt-config";

const restClientBuilder = new RestClientBuilder()
const reqData = <RequestData>{
  httpMethod: 'GET'
}

const jwtConf = <JWTConfig>{
    jwt:'some_jwt'
};
try {
  const client = restClientBuilder.setCredentials(CredentialsType.JWT, jwtConfig).setUrl('http://localhost:8080/test').setRetryOptions({
    retryAttempts: 3,
    exponentialDelay: 2
  }).build();

  const result = await client.call(reqData).toPromise()
  //DO SOMETHING...
} catch (e) {
  //DO SOMETHING...
}

```

* With no Credentials

```typescript
  import {
  RequestData,
  RestClientBuilder,
  RestServiceConfig
  } from "@comparaonline/protocaller"

  const restClientBuilder = new RestClientBuilder()
  const reqData = <RequestData>{
    httpMethod: 'GET'
  }
  
  try {
    const client = restClientBuilder.
    setUrl('http://localhost:8080/test').
    setRetryOptions({
      retryAttempts: 3,
      exponentialDelay: 2
    }).
    build();
  
    const result = await client.call(reqData).toPromise()
    //DO SOMETHING...
  } catch (e) {
    //DO SOMETHING...
  }

```

#### Providing an entire Config
 
  * Config with JWT

```typescript
  import {
    CredentialsType,
    RequestData,
    RestClientBuilder,
    RestServiceConfig
  } from "@comparaonline/protocaller" 
  
  const config = <RestServiceConfig>{
    credentials: {
      type: 'jwt',
      jwt: 'some_jwt'
    },
    retryOptions: {
      retryAttempts: 2,
      exponentialDelay: 2
    },
    timeout: 3000,
    url: 'http://localhost:8080/test'
  }
  const restClientBuilder = new RestClientBuilder()
  const reqData = <RequestData>{
    httpMethod: 'GET',
    headers: {
      'some_header': 1
    }
  }
  
  try {
    const client = restClientBuilder.setConfig(config).build();
  
    const result = await client.call(reqData).toPromise()
    //DO SOMETHING...
  } catch (e) {
    //DO SOMETHING...
  }
```

*  Config with Oauth

```typescript
  import {
    CredentialsType,
    RequestData,
    RestClientBuilder,
    RestServiceConfig
  } from "@comparaonline/protocaller"

  const config = <RestServiceConfig>{
    credentials: {
      "type": 'oauth',
      "realm": "some_realm", // this field is optional.
      "consumer": {
        "key": "some_key",
        "secret": "some_secret"
      },
      "token": {
        "key": "some_key_again",
        "secret": "some_secret_again"
      },
      signature_method: 'HMAC-SHA1' // this field is optional. 'HMAC-SHA1' is the default value 
    },
    retryOptions: {
      retryAttempts: 2,
      exponentialDelay: 2
    },
    timeout: 3000,
    url: 'http://localhost:8080/test'
  }
  const restClientBuilder = new RestClientBuilder()
  const reqData = <RequestData>{
    httpMethod: 'GET',
    headers: {
      'some_header': 1
    }
  }

  try {
    const client = restClientBuilder.
    setConfig(config).
    build();
  
    const result = await client.call(reqData).toPromise()
    //DO SOMETHING...
  } catch (e) {
    //DO SOMETHING...
  }
```

### Mixture between Declarative approach and Config

```typescript
  import {
    CredentialsType,
    OauthConfig,
    RequestData,
    RestClientBuilder,
    RestServiceConfig
  } from "@comparaonline/protocaller"

  const oAuthConf =  <OauthConfig>{
    type: "oauth",
    realm: "some_realm", // this field is optional.
    consumer: {
      key: "some_key",
      secret: "some_secret"
    },
    token: {
      key: "some_key_again",
      secret: "some_secret_again"
    },
  }

  const config = <RestServiceConfig>{
    retryOptions: {
      retryAttempts: 2,
      exponentialDelay: 2
    },
    timeout: 3000,
    url: 'http://localhost:8080/test'
  }
  const restClientBuilder = new RestClientBuilder()
  const reqData = <RequestData>{
    httpMethod: 'GET',
    headers: {
      'some_header': 1
    }
  }

  try {
    const client = restClientBuilder.
    setConfig(config).
    setCredentials(CredentialsType.OAUTH, oAuthConf).
    build();
  
    const result = await client.call(reqData).toPromise()
    //DO SOMETHING...
  } catch (e) {
    //DO SOMETHING...
  }
```

With this last options, notice that you are able to leverage the restClientBuilder pattern. To explain a bit,
you should call first **setConfig(config)** method because it replaces the entire object of configuration inside
the restClientBuilder and then, start to call another methods to override the desired attribute.

In addition, as you may see, exists a lot of ways to declare credentials configs, i.e: 
* With types :
  ```typescript
  const cred = <credential_class_type>{
    // Some configs here
  }
   ```
* With types as attributes:
  ```typescript
  const cred = {
    // ...
    // Some configs here
    type: CredentialsType.OAUTH || CredentialsType.JWT,
    // Some configs here
    // ...
  }
   ```
* With restClientBuilder: 
  ```typescript
    const restClientBuilder = new RestClientBuilder()
    
    try {
      const client = restClientBuilder.
      setConfig(config).
      setCredentials(CredentialsType.OAUTH || CredentialsType.JWT, some_conf).
      build();
      //DO SOMETHING...
    } catch (e) {
      //DO SOMETHING...
    }
  ```

There is no "Correct" way, it is just matter of what you like better.


#### NOTES

  * retryOptions: Its mission is simple, provides configurations to retry a request. You may notice that there 
    are two options, **retryAttempts**: this tells to the client how many requests should make in case of error.
    **exponentialDelay**: this tells to the client how much should wait to make next rest call.
    **retryOptions** is an optional attribute, by default is set as following:
```text
 {  
    retryAttempts: 2,
    exponentialDelay: 2
 }
```

  * Always calls **build** method, to generate the client.


### Soap Calls

 *In construction

## Third parties 🛠️

* [Axios](https://github.com/axios/axios) - Library to built http request
* [Rxjs](https://www.learnrxjs.io/) - Library to handle streams of data
