New Project: Adonis-Hexa—a smarter way to develop, build & maintain scalable Adonis applications.

in #utopian-io6 years ago

Repository

https://github.com/creatrixity/adonis-hexa

Adonis Hexa Brand

New Project: Adonis Hexa

What is Adonis Hexa about?
Adonis Hexa is a software development paradigm for maintaining a scalable application architecture while developing apps for the AdonisJS framework.

The main reason we use Adonis Hexa is to reduce the amount of technical debt incurred over the lifetime of a project. By providing a stable, reliable set of architectural patterns, we are able to assure that our codebase is really determinist and straightforward.

Technology Stack

  • AdonisJS: >=4.1.0
  • Node.js
  • Chai.js

Roadmap

  • Develop Adonis Hexa core—Create a stable base blueprint for future contributions to Adonis Hexa.
  • Create a CLI generator—To greatly ease development experience with Adonis Hexa, a command line interface will be developed to execute mundane, repetitive tasks.
  • Create an NPM module—We plan to create an NPM module for Adonis Hexa within the next iterations.
  • Create a visual user interface accessible over the web.

How to contribute?

Found a bug? You may raise an issue. Created a fix for a bug you encountered? Please make a pull request. Want to talk? Contact me via [email protected] or post a tweet @creatrixity

GitHub Account

https://github.com/creatrixity

How do I use Adonis Hexa for my next AdonisJS project?

Simply head over to https://github.com/creatrixity/adonis-hexa and clone the repo as it provides a stable base to get you started.

git clone https://github.com/creatrixity/adonis-hexa.git

...then run npm install.

Then run the following command to run startup migrations.

adonis migration:run

Exploring building a feature with Adonis Hexa

To explore a genuine real-world use case for Adonis Hexa, we'll be leveraging Adonis Hexa to add the search feature to an application that requires us to be able to find users by sending data to an API endpoint. After carrying out our installation steps. We'll add the adonis-search package to help with building out our search feature. Add this line to the dependencies object in package.json at the root.

"dependencies": {
    "adonis-search": "^1.0.3",
    // ....
}

We'll also add its service provider to our service providers. Add this service provider to start/app.js.

const providers = [
  "adonis-search/providers/QueryProvider"
  //...
];

We then install all dependencies.

npm install

We'll need to add a search route available at /users/search. Add this route to src/Services/Api/Routes.js.

{
  route: "users/search",
  controller: "UserController.getSearchUsers",
  method: "get"
},

The Hexa way to do routing is a little different from regular Adonis routes. Our controller UserController.getSearchUsers means we are using the getSearchUsers method of the UserController class and we are handling GET requests.

We'll add the getSearchUsers method to the UserController.

getSearchUsers ({ request, params }) {
    return this.serve('Api/Features/SearchUsersFeature', {
        request
    });
}

This is a one-liner method that simply "runs" the SearchUsersFeature. The SearchUsersFeature will assemble the jobs that do the actual user searching. We'll create src/Services/Api/Features/SearchUsersFeature.js.

"use strict";

const BaseFeature = use("Src/Foundation/BaseFeature");
const UserRepository = use("Src/Data/Repositories/UserRepository");

/**
 * Searches through and returns users with their username or email matching provided queries.
 *
 * **Namespace**: `Src/Services/Api/Features/SearchUsersFeature` <br />
 *
 * @class SearchUsersFeature
 */
class SearchUsersFeature extends BaseFeature {
  constructor(params) {
    super(params);
  }
  /**
   * Contains code that will be ran when this feature is invoked.
   *
   * @method handle
   *
   * @return {Object} JSON
   */
  async handle() {
    const { request } = this.params;

    const query = await this.run("User/Jobs/CreateUserSearchQueryJob", {
      request
    });

    const users = await this.run("User/Jobs/RetrieveUsersJob", {
      query: query.search(["username", "email"])
    });

    return {
      users
    };
  }
}

module.exports = SearchUsersFeature;

We get the request object (available within this.params in all Hexa controllers) and then pass it to the CreateUserSearchQueryJob. This job will create a search query object that we'll pass to the RetrieveUsersJob as a query. The RetrieveUsersJob will return users matching the search query provided.

Let's create src/Domains/User/Jobs/CreateUserSearchQueryJob.js.

"use strict";

const BaseJob = use("Src/Foundation/BaseJob");
const UserRepository = use("Src/Data/Repositories/UserRepository");
const Query = use("Query");

/**
 * Creates a user search query.
 *
 * **Namespace**: `Src/Domains/User/CreateUserSearchQueryJob` <br />
 * **Singleton**: No <br />
 * **Alias**: None
 *
 * @class CreateUserSearchQueryJob
 * @constructor
 */
class CreateUserSearchQueryJob extends BaseJob {
  constructor(params) {
    super(params);
  }

  /**
   * Contains code that will be ran when this job is invoked.
   *
   * @method handle
   *
   * @return {Object} Lucid/ORM
   */
  async handle() {
    const query = new Query(this.params.request, {
      order: "id"
    });

    return query;
  }
}

module.exports = CreateUserSearchQueryJob;

We use the adonis-search package to process our search query. We make sure our search results are ordered according to their id property.

Let's create src/Domains/User/Jobs/RetrieveUsersJob.js.

"use strict";

const BaseJob = use("Src/Foundation/BaseJob");
const UserRepository = use("Src/Data/Repositories/UserRepository");

/**
 * Retrieves users matching query.
 *
 * **Namespace**: `Src/Domains/User/RetrieveUsersJob` <br />
 *
 * @class RetrieveUsersJob
 * @constructor
 */
class RetrieveUsersJob extends BaseJob {
  constructor(params) {
    super(params);
  }

  /**
   * Contains code that will be ran when this job is invoked.
   *
   * @method handle
   *
   * @return {Object} Lucid/ORM
   */
  async handle() {
    const { query } = this.params;
    const userRepo = new UserRepository();

    const users = await userRepo.pageWhere(query);

    return users;
  }
}

module.exports = RetrieveUsersJob;

We use the pageWhere method freely available to us thanks to the Repository class that comes with Hexa. This allows us to return results in pages just like Google would.

We've now been able to add a completely reusable feature alongside two completely reusable jobs. This is the power of Adonis Hexa.

Testing approach.

We leverage Chai assertions for testing which are compatible with AdonisJS test runners. Read this article to learn more.

So, what can we create with Adonis Hexa?

Adonis Hexa allows you to speed up your coding cycles by keeping code reusable. Let your imagination run wild and go creative with it.

Below is the screenshot of an app with the SearchUsersFeature reused to find items for a fast food ordering app.

Screenshot of the Search User Feature

Sort:  

Thanks for the contribution, @creatrixity! Looks like an interesting project that has had a lot of work put into it - amazing work!

I don't really have any feedback to give about the code, as it's great, so I'll just say this: it would be great if you could link the relevant commit(s) and/or pull request(s) in the body of your contribution.

Looking forward to see how this project evolves!


Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Thanks @amosbastian. All subsequent pull requests will be posted here alongside relevant commits. Thanks for the heads up!

Thank you for your review, @amosbastian!

So far this week you've reviewed 7 contributions. Keep up the good work!

I upvoted your post.

Keep steeming for a better tomorrow.
@Acknowledgement - God Bless

Posted using https://Steeming.com condenser site.

Hi @creatrixity!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @creatrixity!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Congratulations @creatrixity! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

Award for the number of upvotes

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

SteemitBoard Ranking update - Resteem and Resteemed added

Support SteemitBoard's project! Vote for its witness and get one more award!

Coin Marketplace

STEEM 0.28
TRX 0.13
JST 0.032
BTC 60385.11
ETH 2889.75
USDT 1.00
SBD 3.65