Giter VIP home page Giter VIP logo

stex's Introduction

Stex

An opinionated web framework built upon expressjs

Express is nice, but bare. Rails has many great features, but can be overkill for json microservices. Stex aims to be a point in the middle. It does this by making a few opinionated choices with how you solve the recurrent problems of building a production ready web application. Namely, it makes choices for you regarding: configuration, logging, database access, database schema management, error handling, error reporting, and more.

Lets look at what Stex provides in each of these areas:

Configuration

Configuration within stex is managed by nconf, and your configuration files are laid out in a manner similar to how rails handles configuration. You application will have a directory called /config and that folder will contain files named corresponding to the NODE_ENVs they apply to. development.json and production.json would be examples. In addition, there is a special file allowed named all-envs.json that lets you set defaults for your config that can be overriden in more specific environments.

Stex exposes a global var conf through which you can get access to your configuration. Say for example you have a config file that looks like so:

{
  "showStackTraces": true,
  "logLevel": "debug",
  "PORT" : 3000
}

Executing conf.get("showStackTraces") will return true. Simple enough, eh?

Logging

Logging is provided via bristol and exposed through another handy global: log. In addition to the human-friendly console output that you get when your logTarget config variable is set to humanizer, you can also get easily scriptable json logs sent to syslog if you set your target to syslog

Out of the box, we log data pertaining to every request coming in and every response leaving your application. We also log every uncaught error. In the future, we will log every db query.

TODO: describe more about the json-based logging system

Database Access

Rather than going straight to bundling an ORM, we're starting stex of with just knex. We expose a knex client to you under the global db, such that you can write code like so:

db("users").where("id", id).select()

Database Schema Management

Knex is great for query building, but Knex for data migration is a bit underbaked at the moment. Given that, we've decided to leverage db-migrate instead for db migrations.

TODO: go into details, fool

Error Handling

Stex installs a set of middleware to make the unhandled error story of your app a little less hands on. Stex provides a simple 404 handler for you, and will render a standardized response to the client (plus sending error data to your log) for any error that makes it past your custom middlewares.

Error Reporting

In addition to your local logs, we bundle support for sentry meaning that if you supply a configuration value for sentryDsn we will automically start reporting error data to sentry for you.

And More...

Stex CLI

The Stex CLI is your gateway. It provides a series of subcommands that should help you in your day-to-day: www, console, db-console, db-migrate and humanize-logs. We'll go through each one:

stex www

Starts up a server process. Add the option --watch to have stex watch your directory for file changes and automatically restart itself when it needs to.

stex console

Opens up a REPL with the Stex application globals loaded.

stex db-console

Opens up a MySQL console given the current configuration

stex db-migrate

TODO

Gulp

TODO

Testing

TODO

Lifecycle

A Stex application has, at present, 4 different lifecycle events that happen:
init, activate, boot, and finally shutdown.

Init

Loading your stex application (by requiring your app.js) will initiate the 'init' event, and will initialize as much of the framework as possible... notably it will allow you to use the logging and configuration infrastructure of the app.

Activate

Stex is not designed to have multiple concurrent stex applications running in the same process; By taking this stance, we allow you to make your app code more concise by relying upon a curated set of global vars we think most of your code needs access to. Activation is the lifecycle event that installs these global vars.

Boot

Everything else needed to get your application loaded runs during the boot event. Database connections, middleware installation, routing definitions, and heavy work.

Shutdown

Can be triggered to force db connections to close, etc. so that your process can gracefully terminate.

stex's People

Contributors

bartekn avatar bekkibolthouse avatar joshbeal avatar lookis avatar matschaffer avatar nullstyle avatar thejollyrogers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stex's Issues

A argument for an auto-loading stex

tl;dr; We should both standardize the directory layout of stex for both "model" and "controller" files and automatically load them at stex initialization

Problem

The CommonJS model for adding module dependencies is nice for being explicit about inter-module dependencies and has overall led to much better javascript code. However, it can lead to very large sections of "require" blocks at the top of each file that can distract from the function of the module, and more importantly it leaves each module the freedom to name the symbols that it imports, leading to naming inconsistencies:

// in module 1:
var wallet = require('wallet');

// in module 2:
var Wallet = require('wallet');

Furthermore, within a single node project you are forced to use relative requires, leading to friction when you restructure your project or rename a file:

// when in a sibling module
var wallet = require("./wallet")

// when in a child module
var wallet = require("../wallet")

Proposal

There exists a set of modules within a stex application that are used quite often throughout nearly all the other modules in a stex application: the "models" and the "controllers". By automatically loading these files we will reduce duplication and increase clarity. I propose we automatically load files underneath /lib/controllers and /lib/models. For example, the routes file (app.js) could go from this:

var walletsCtrl = require("./controllers/wallets")
var totpCtrl    = require("./controllers/totp")
var recoverCtrl = require("./controllers/recovery")

router.post("/v2/wallets/create", walletsCtrl.create);
router.post("/v2/wallets/update", walletsCtrl.update);
router.post("/v2/totp/enable",    totpCtrl.enable);
// etc.

to:

router.post("/v2/wallets/create", stex.controllers.wallets.create)
router.post("/v2/wallets/update", stex.controllers.wallets.update)
router.post("/v2/totp/enable",    stex.controllers.totp.enable);
// etc.

redis authentication

is it possible to use remote authenticated redis DB's with stex? error is:

Error: Ready check failed: NOAUTH Authentication required.

New Initialization system

Similar to the rails initializer system, the stex initializer system will allow applications to define custom "startup" and "shutdown" functions as well as a dependency mechanism to allow code inside an initializer to leverage other portions of the framework

Promise-enabled REPL

STORY

As a developer running in a stex console process, I want to be able to execute javascript that returns a promise which is then resolved before printing, so that I can have a more friendly asynchronous experience when using the REPL.

RATIONALE

Presently, the stex repl process is very bare-bones... simply using the built in node 'repl' module with no customization. Given that most of the useful code in node is asynchronous (and for stex, promise-based), the repl is quite hard to use because you pretty much end up having to write lines like: db("wallets").where("id", id).select().then(console.log)

This is a pain and slows down the explorative experience of a repl, IMO. It would nicer instead if we built a repl that saw the return value of a statement was a Promise, resolve it, then printout the value for the developer... essentially automating the .then(console.log) part.

Add "stex.reportError" helper function

It's come to my attention that in stellar-api we're forwarding any call to stex.error.log to sentry. This is not a good situation. It means that error reports in stellar-api are actually just log lines that alias most of the useful information encoded into a Error object. It seems that this solution was chosen because we did not have defined with stex a reusable system to report errors.

We should add this functionality at stex.reportError which should behave similar to the stex errors middleware: It logs as well as reports to sentry as peer operations, not dependent ones. From the code:

    var reportErrorDirectly = function(err) {
        log.error(err.message);
        // report to sentry if we are enabled
        if(sentry) {
            sentry.captureError(err);
        }
    };

I propose we extract that functionality to a method stex.reportError, such that the above code becomes:

    var reportErrorDirectly = function(err) {
        stex.reportError(err);
    };

Provide a "unique request id" in stex.log

When a stex application recieves a request, it would be nice to attach a unique id to every log that arrises from that request. that way logs could be tracked by request id. the asynchronous nature of node makes this hard as you lose context in the callback after the event loop.

here's a potential solution or model we could use https://datahero.com/blog/2014/05/22/node-js-preserving-data-across-async-callbacks/

Ideally most of the functionality would be abstracted into Stex, and all the client would need to do is add some stex speicific middleware to their request chain, and any further call to Stex.log will automatically add that request id to the log.

Unrecoverable Error: Cannot enqueue Query after fatal error.

If a connection is killed by mysql, or the running stex application otherwise gets its connection into a fatal state, stex does not properly recover and the service requires a restart to resume normal function.

Instead, stex needs to validate/reconnect to the db at the HTTP request boundary if no connection is available, and we need to close connections after we receive a fatal error.

Add "scripts" support

STORY

As a developer building an application on top of stex, I would like to be able to easily defined multiple entrypoints for my application, so that I can build one-time processes, cron-based repeated jobs, or multiple web service APIs on top of one codebase

RATIONALE

Presently, there are only 2 types of processes that can be started on top of stex... the www process started via stex run www and the repl process started via stex console. The goal of this issue is to unify how we launch processes within stex as well as enable an application to define their own entrypoints.

For example, you may have a custom job queue running process that you want run within the stex ecosystem (giving access to the db,log,conf globals). Or you may have written a database cleaning process to resolve some prior corruption.

DESIGN IDEAS

The following paragraph describes a possible design:

Every stex application has a top-level folder called scripts. By default, it is populated with 2 files: www.js, and console.js. These two scripts can be launched with either stex run www or stex run console respectively.

A script launched in this manner (via stex run NAME) will execute after having the stex ecosystem loaded and initialized.

A developer can define additional scripts simply by creating new files within the scripts folder, which can then be run as expected by executing stex run. In this way, stex run NAME is just an alias for:
node scripts/NAME.js.

publish stex to npm

Stex is not yet published on the public npm repository. Would it be possible to add it ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.