Repository
[https://github.com/adonisjs](AdonisJS Repository)
What Will I Learn?
At the end of this tutorial, we should have a fully functional Adonis package. We'll cover the following concepts.
- Setting Up Package Specific Data Management.
- Writing to The Filing System through NPM.
- Writing Tests For Our Package with Japa.
Requirements
- https://nodejs.org/ 8.0 or greater.
- https://npmjs.com/ 8.0 or greater.
- https://yarnpkg.com/ package manager.
- https://github.com/
- An intermediate level of https://adonisjs.com/ knowledge.
- [https://github.com/creatrixity/sophos](Sophos Github Code)
- Keen interest and patience.
Difficulty
- Intermediate
Let's Get Straight To Work.
If we head back into our src/Sophos.js, we begin our class with the following lines:
class Sophos {
sourceURL = 'https://wisdomapi.herokuapp.com/v1/';
}
Not good. Our resource endpoint is not flexible. We can do better by making this configurable by our end user. To do this, we'll add an array of objects to our configuration file which we'll be using to allow us switch resource endpoints effortlessly.
Heading back into config/index.js, let's make some changes; we'll change the sourceURL string property to a sourceURLs object to help us accommodate a wider range of options.
/* */ module.exports = { */ We added two key-value pairs to our sourceURLs map for resources mapping to various quote categories. Next, we simply need to modify our Sophos class to accommodate the changes. The Sophos class makes a request to a url returning a promise resolved with data or rejected with an error. @class Sophos @param {Object} Config constructor (Config) { getQuotes (category = 'startups') { } Great, we've just added some more custom options to our code. Our package is now capable of fetching quotes on design or startups from two different URLs. We also added a check to make sure our users request a supported category. If our check fails, we reject the promise and return a little error message to our user. We'll be adding some functionality that requires data management practices. We'd like users to be able to be able to store a collection of favorite quotes simply by providing a user_id and the URL of the resource of interest. To do this, we'd need to publish migration files to the database/migrations folder of the Adonis application leveraging this package. Let's create our templates/SophosQuoteSchema.js migration template. const Schema = use('Schema') class SophosQuoteSchema extends Schema { down () { module.exports = SophosQuoteSchema This migration template will be published to database/migration at installation. We are creating tables with the sophos namespace to prevent namespace collisions between our package migrations and other third party package migrations. This is a pretty good time to add an accompanying Lucid model for our SophosQuotes schema. Let's create templates/SophosQuote.js and add some code. const Model = use('Model') class SophosQuote extends Model { /** module.exports = SophosQuote We'll update instructions.js to copy our migrations and models at runtime. Open up instructions.js and modify as below. const path = require('path') async function copyQuoteMigration (cli) { async function copyQuoteModel (cli) { async function makeConfigFile (cli) { module.exports = { Comparing our updated instructions.js module to our previous instructions.js module, you'll notice we abstracted our code into a series of async functions. We then export these asynchronous functions in module.exports. We'd love to provide a means for our users to be able to save their favorite quotes for ease of use at a later date. To do this, we must add a model string property to our config specifying the proper model we'll be using to save this information. Its important to note that, when you're developing packages, you should prioritize ease of customization above every other criteria. We'll add this setting to our config/index.js file. */ } Next, we'll write a bit of functionality to the src/Sophos class. We'll add the asynchronous saveQuote method. If the method fails to receive any attributes as an argument or if the attributes supplied is not an object, we throw an error and keep it movin'. Next, we call the this._getModel method that we define below. Next, we need to provide a method that allows us to return the saved quotes (or quote, as the case may be). We'll call this method getSavedQuotes and define it below. Here, we'll return a single Quote object if an id is provided and an array of Quote objects otherwise. We're doing great! Now all we need to do is write some tests for our code. A good package is properly tested. We'd like to write tests for our package and we can do this with the help of the Japa NPM module. Let's start by creating a file called japaFile.js. It will help us run our tests. const cli = require('japa/cli') Next, we'll be writing a couple of tests. We'll be testing the save and retrieve quote functionality which we just wrote. Let's add some assertions and code. /* const test = require('japa') test.group('Sophos', () => { }) Here, we are writing a couple of assertions that utilize our Sophos class. We are making sure the data passed to our class methods return expected values. We've covered some pretty important concepts in this tutorial. We examined a different approach to providing a configurable package. We also setup package specific data management and we wrote tests for our package. Finally, we published our package to the NPM registry available at https://www.npmjs.com/package/adonis-sophos [https://docs.npmjs.com/getting-started/publishing-npm-packages](Publishing NPM Packages - NPM Docs) [http://quotesondesign.com/](Quotes on Design API)'use strict'
|--------------------------------------------------------------------------
Sophos Sophos returns bits of inspiration for your next big design and startup ideas.
/*
|--------------------------------------------------------------------------
Source URLs The URLs of various resources queried for data.
sourceURLs: {
'startups': 'https://wisdomapi.herokuapp.com/v1/random',
'design': 'http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1'
},
} /**
*/
class Sophos {
sourceURLs = {};
this.config = Config.merge('sophos', {
sourceURLs: this.sourceURLs
})
}
return new Promise((resolve, reject) => {
if (!this.config.sourceURLs.hasOwnProperty(category)) {
reject({
error: Sorry, Sophos does not support requests for "${category}" at the moment.
})
} let endpoint = `${this.config.sourceURLs[category]}`
request(endpoint, { json: true }, (err, res, body) => {
if (err) return reject(err);
return resolve(body)
});
});
}Writing to the Filing System Using the CLI Helper.
'use strict'
up () {
this.create('sophos_quotes', table => {
table.increments()
table.integer('user_id').notNullable();
table.string('quote_url', 80).notNullable()
table.timestamps()
})
}
this.drop('sophos_quotes')
}
}'use strict'
*/
user () {
return this.belongsTo('App/Models/User')
}
}'use strict'
try {
const migrationsFile = cli.helpers.migrationsPath(${new Date().getTime()}_sophos_quote.js
)
await cli.copy(
path.join(__dirname, 'templates', 'SophosQuoteSchema.js'),
path.join(migrationsFile)
)
cli.command.completed('create', migrationsFile.replace(cli.helpers.appRoot(), '').replace(path.sep, ''))
} catch (error) {
// ignore error
}
}
try {
await cli.copy(
path.join(__dirname, 'templates', 'SophosQuote.js'),
path.join(cli.appDir, 'Models/SophosQuote.js')
)
cli.command.completed('create', 'Models/SophosQuote.js')
} catch (error) {
// ignore error
}
}
try {
const inFile = path.join(__dirname, './config', 'index.js')
const outFile = path.join(cli.helpers.configPath(), 'sophos.js')
await cli.copy(inFile, outFile)
cli.command.completed('create', 'config/sophos.js')
} catch (error) {
// ignore error
}
}
await makeConfigFile(cli)
await copyQuoteModel(cli)
await copyQuoteMigration(cli)
}Setting Up Package Specific Data Management
module.exports = {
/*
|--------------------------------------------------------------------------
Model The model to be used for Sophos' quotes
model: 'App/Models/SophosQuote', /*
* Saves a quote for referencing later.
*/
async saveQuote (attributes = null) {
if (!attributes || typeof attributes !== 'object') throw('Required argument "attributes" was not provided.');
const quote = await this._getModel().create(await)
}_getModel () {
return use(this.config.model);
}/*
* Returns all saved quotes.
* If an id param is provided, returns a single quote.
*/
async getSavedQuotes (id = nulll) {
let self = this;
return new Promise((resolve, reject) => {
if (id) {
return resolve(
await self._getModel()
.query()
.where('id', id)
.first()
)
}
// return all saved quotes.
return await self._getModel().query();
});
}</code>
Writing Tests For Our Package with Japa.
'use strict'
cli.run('test/*/.spec.js')'use strict'
*/
const { Config } = require('@adonisjs/sink')
const Sophos = require('../src/Sophos')
test('should save a quote to the database', async (assert) => {
const data = {
user_id: 1,
quote_url: 'https://quotesondesign.com/apple-commercial/'
}; let result = null;
const Sophos = new Sophos()
Sophos.saveQuote(data).then(quote => {
result = quote
}).catch(err => console.log(err))
assert.equal(result.user_id, data.user_id)
assert.equal(result.quote_url, data.quote_url)
})
test('should retrieve quote #1', async (assert) => {
const id = 1;
let result = null;
const Sophos = new Sophos()
Sophos.getQuotes(data).then(quote => {
result = quote
}).catch(err => console.log(err))
assert.equal(result.id, id)
})
Conclusion
Resources
Flagged for Plagiarism
@steemflagrewards
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Steem Flag Rewards mention comment has been approved! Thank you for reporting this abuse, @flugschwein categorized as plagiarism. This post was submitted via our Discord Community channel. Check us out on the following link!
SFR Discord
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Unfortunately your prior temporary ban did not yield the proper results, and you are still copying content from the web.
"Previously, we added functionality that allowed us to fetch an inspirational random quote concerning startups from the ..." , seriously?
You have been permanently banned from receiving Utopian reviews.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Hello @mcfarhat I do not take the content on the web,, do you have any proof before you permanently ban me?
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit