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.
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 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.
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.
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:
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.
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.
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
const path = require('path')
- Add the path to the new provider in the
providers array
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 usingconst 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 theconfig/Sms.js
file, we add the class to interact with the helper library in theproviders/sms/src
folder to handle it. The class will contain theto
method, thebody
method and thesendSms
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 theconfig/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.