# Wrapping NPM Packages as a Service Provider in AdonisJs

AdonisJs makes creating APIs fun, it makes dependency importing into a file easy with the `use` global method. It gives the developer a central point to configure their dependencies and bind it to the IOC container. To read about the IOC container  [click here](https://adonisjs.com/docs/4.1/ioc-container#_binding_dependencies). 
This article will show you how to use AdonisJs service providers to achieve all the benefits mentioned earlier, including configuring different dependencies serving a similar purpose to have a single interface and a central point to switch from one dependency to the other without altering the code.
I will be demonstrating using the Twilio Node.js helper library, I will assume you are already working with AdonisJs but if you need to learn about adonisJs you can follow [this link](https://adonisjs.com/docs/4.1/installation) and have a basic understanding of object-oriented programming. 

## Getting Started
First, we install the Twilio helper library using `npm`, if you prefer you can use `yarn`. `npm install twilio` into the project.
## Setting up Configuration
So we open up the `config` folder and create a file in it called `sms.js`. The configuration object will be created in such a way that it can contain various SMS service providers configuration details. The details will be fed from the environment file.
```javascript
const Env = use('Env')

module.exports = {
  /*
  |--------------------------------------------------------------------------
  | Connection
  |--------------------------------------------------------------------------
  |
  | Connection to be used for sending SMS. 
  | A connection needs to have a corresponding object below.
  |
  */
  connection: Env.get('SMS_CONNECTION'),
  sms_sender: Env.get('SMS_SENDER'),
  /*
  |--------------------------------------------------------------------------
  | TWILIO
  |--------------------------------------------------------------------------
  |
  | Here we define the configuration for sending SMS via TWILIO.
  |
  */
  twilio: {
    driver: 'twilio',
    accountSid: Env.get('TWILIO_SMS_ACCOUNTS_ID'),
    auth_token: Env.get('TWILIO_SMS_AUTH_TOKEN')
  },
}
``` 

The `connection` determines which SMS service provider the system is using, `sms_sender` defines the number sending the SMS, `twilio` is the object containing the configuration details for the Twilio SMS service provider, any other service provider needed can be configured by adding the configuration object like the `twilio` object.

## Setting up the Providers Folder
The `providers` folder will contain all providers and will live in the root of your app. In the `providers` folder we create a folder called Sms, here is where all the magic will happen.
```
|-- app
| |--config
| |-- providers
|   |-- sms
| |-- start
```

## Setting the Source folder 
In the newly created `providers/sms` folder, we need to have a folder where the code interacts with the npm package. the folder will be named `src`, which will contain an `index.js` file and other files for the different SMS service providers. In this demo, we will call it a `Twilio.js` file which will contain the class that interacts with the Twilio node.js helper function.
```javascript
const Twilio = require('twilio')

class TwilioDriver {
  constructor (config, sender) {
    this.config = config
    this.messageBody = null
    this.sendTo = null
    this.sender = sender
  }

  to (to) {
    this.sendTo = to
    return this
  }

  body (body) {
    this.messageBody = body
    return this
  }

  async sendSms () {
    const client = Twilio (this.config.accountSid, this.config.auth_token)
  
    return await client.messages.create ({
      body: this.messageBody,
      from: this.sender,
      to: this.sendTo
    })
  }
}

module.exports = TwilioDriver

```
Next, we create an `index.js` file in the `src` folder, the file will `require` other files in the `src` folder, pass it into an object and export the object. The `index.js` file will look like this:
```javascript
module.exports = {
  twilio: require('./Twilio')
}
``` 

## Creating the Service Provider index file
This file takes in the `config` file and the `index.js` file from the `src` folder, it will reside in the `Sms` folder. It takes in the connection property of the `config` file and decides which SMS service provider to instantiate.
```javascript
const Driver = require('./src')

class Sms {
  constructor (Config) {
    this.Config = Config
  }

  prepare () {
    /**
     * Read connection name using Config
     * provider
     */

    const SmsConfig = this.Config.get('sms')
    const name = SmsConfig.connection
    const sender = SmsConfig.sms_sender
    const config = SmsConfig[name]

    const SmsDriver = Driver[name]


    /**
     * Return the instance back
     */
    return new SmsDriver (config, sender)
  }
}

module.exports = Sms

```

## BInding to the IOC container
Here we use service provider to bind all our previous work to the IOC container. The service provider is a class we extend, it comes with a register and a boot method but we only need to use the register method. In the register method, the configuration from the `config` file is passed into the `Sms` class located in the `sms/index.js` file. The first parameter of this.app.bind defines the name used to address the provider when importing it later for use.
```javascript
const { ServiceProvider } = require('@adonisjs/fold')

class SmsProvider extends ServiceProvider {
  register () {
    this.app.bind('Sms', () => {
      const Config = this.app.use('Adonis/Src/Config')
      return new (require('.'))(Config).prepare()
    })
  }
}

module.exports = SmsProvider
```
`this.app` references the `ioc` object, so we can use `this.app.bind` or `this.app.singleton` and it will be the same with `ioc.bind` or `ioc.singleton` 

## Registering the Provider
To register the newly created provider, open the `app.js` file in the `start` folder in the root of the app.
- require the path module
```javascript
const path = require('path')
```
- Add the path to the new provider in the `providers array` 
```javascript
const providers = [
  path.join(__dirname, '..', 'providers', 'sms/Provider'),
]
```
## Using the Provider
At this point, we can import the provider into any part of the project using
```javascipt
const Sms = use('Sms')
```
## Moving Further
So if there is a need to use another SMS service provider nodeJs helper library, we add the configuration to the `config/Sms.js` file, we add the class to interact with the helper library in the `providers/sms/src` folder to handle it. The class will contain the `to` method, the `body` method and the `sendSms` method. So as not to break existing code. Finally, remember to define the new name of the service provider in the `.env` file and let it be the name of one of the properties in the  `config/Sms.js` file holding a configuration object.

In conclusion, we have seen have to configure an NPM package as a service provider for AdonisJs, the principles remain the same and a `Provider.js` file is always necessary, the rest are  defined based on the needs of the developer.
