Code Monkey home page Code Monkey logo

core's Introduction

Denali

CircleCI Coverage Dependencies npm downloads latest version

An opinionated Node framework for building robust JSON APIs

Denali is a tool to help you build and deliver amibitous JSON APIs. It features:

  • First class JSON serializers, including out of the box JSON-API support
  • A single controller class (called Actions) per endpoint
  • Flexible, declarative filter system
  • An emphasis on developer happiness - a robust CLI, powerful testing primitives, and support for the full lifecycle of app development
  • ORM-agnostic design - choose your favorite Node ORM, or none at all

Why Denali?

Denali should feel familiar to anyone who has worked with popular MVC frameworks like Rails. But Denali has a slightly unique take on each aspect of the MVC pattern:

(M)VC - ORM Adapters instead of ORM lock-in

Unlike many server frameworks, Denali lets you choose which ORM you'd like to use. ORMs are hard, and the Node ecosystem has multiple competing options, each with it's own strengths and weaknesses. Rather than limiting you to a single "official" ORM, or worse, attempting to roll our own, Denali uses an adapter system to ensure that whatever ORM you bring, it can work with the Denali ecosystem.

M(V)C - Serializers instead of Views & Templates

Denali's view layer is unique as well. Rather than traditional HTML rendering, Denali's view layer renders JSON. Instead of the usual templates and view classes, we have Serializers instead, which tell Denali how to render the data you supply as a response. The separation of responsibilties ensures you can tweak how your data is structured in your API without having to change any of the logic of your app. Several common formats, including JSON-API, are supported out of the box, and customization is easy.

MV(C) - Actions instead of Controllers

In Denali, the Action class takes the role of the controller in the application. But rather than a single controller class that responds to many different endpoints, an Action class is responsible for responding to requests against a single endpoint (URL + method) only. The result is powerful - since the Action class directly and completely represents the app's response handler, we can use expressive declarative syntax to succinctly define behaviors.

Getting Started

You can install Denali globally via npm:

$ npm install -g denali denali-cli

Create a new application (run with Node 6.0+):

$ denali new my-api
$ cd my-api

You can use the server command to run your API locally in development mode. The API server will automatically restart when you make a change:

$ denali server

To learn more, check out the docs or join us on Slack

License

MIT © Dave Wasmer

core's People

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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

core's Issues

Investigate proxy performance

There are a variety of older comments around the web about proxies being fairly slow. We should investigate whether the performance hit (if it exists) is significant enough to warrant refactoring them out (keeping in mind the potential for future optimizations from runtimes)

Load & performance testing

The testing framework could provide the ability to test performance of various endpoints, potentially failing if they fall below certain thresholds. Even better, they could fail if the reduced performance by more than X% since last change, but that requires cooperation from the test runner / CI environment potentially.

Email Service

Is this a thing yet? Just wondering because it's documented here.

I couldn't find any hint of the mailer being integrated into actions.

Support arbitrary blueprint sources

When I run $ denali generate, I should be able to supply:

  • A local directory, i.e. $ denali generate ../some/local/dir
  • A git url, i.e. $ denali generate https://bitbucket.org/user/some-cool-blueprint
  • A github repo? i.e. $ denali generate user/some-cool-blueprint

Support async/await by default

Main use case is to make Action.perform cleaner by using syntax like

async perform(params) {
  let User = this.modelFor('user');
  let mailer = this.service('mailer');
  let user = await User.find(params.id);

  mailer.send('welcome', user);

  return user;
}

Initial Stub Results

I tried the async-generator transform and am getting the following error:

Error building your app:
Error: /Users/iradchenko/battleground/test/app/actions/index.js: You gave us a visitor for the node type "ForAwaitStatement" but it's not a valid type
    at verify (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/visitors.js:196:13)
    at Object.explode (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/visitors.js:72:3)
    at traverse (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/index.js:77:12)
    at NodePath.traverse (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/path/index.js:144:25)
    at exports.default (/Users/iradchenko/battleground/test/node_modules/babel-helper-remap-async-to-generator/lib/index.js:10:8)
    at PluginPass.Function (/Users/iradchenko/battleground/test/node_modules/babel-plugin-transform-async-to-generator/lib/index.js:13:56)
    at newFn (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/visitors.js:276:21)
    at NodePath._call (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/path/context.js:76:18)
    at NodePath.call (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/path/context.js:48:17)
    at NodePath.visit (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/path/context.js:105:12)
    at TraversalContext.visitQueue (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/context.js:150:16)
    at TraversalContext.visitSingle (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/context.js:108:19)
    at TraversalContext.visit (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/context.js:192:19)
    at Function.traverse.node (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/index.js:114:17)
    at NodePath.visit (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/path/context.js:115:19)
    at TraversalContext.visitQueue (/Users/iradchenko/sandbox/denali/node_modules/babel-traverse/lib/context.js:150:16)

Emailing

Denali should expose a common framework for sending emails (other notifications? push? text?). This would allow addons to supply notifications out of the box, without caring about SMTP details or templating engines.

docs command

Denali could expose a docs CLI command. This would serve up the Denali documentation for the version in use on a local server. It could also generated automated docs for the API based on analysis of the Action classes.

Action classes could provide a hook (i.e. docs()) that returns information about the action in question. Addons could provide additional rendering capabilities (i.e. a validation addon could render an "allowed params" section, and could add data to the "possible errors" section of the docs() hook payload).

Limit loaded to config to current environment only

RIght now, Denali just loads any config it can find, and leaves it to the application code to extract the right values from the right environments. Ideally, we would only load the config unique to this environment.

Config loading can be a point of contention, as well as a blocker for some more esoteric use cases (if the chosen method of config loading turns out to not support a specific use case). I think a good solution here would have strong conventions around the 80% use cases, with escape valves for those edge cases we can't anticipate or don't want to support otherwise.

Support TLS out of the box

Denali apps should include TLS by default, if possible. We could use self-signed certs in dev mode, or potentially bake in a first class integration with LetsEncrypt.

Clean up deps/devDeps

In Denali's package.json, as well as the app/addon blueprint package.json, we probably need to move some of the devDeps out to regular deps (see this comment). There also appears to be some duplicates in the app/addon blueprints.

[Idea]: Using decorators for defining routes

Issue

Currently the way that routes are defined creates a big gap between the route definition and implementation. So your controllers have some methods and they might be named what the route is, but who knows really, until you look at config/routes.js. So there is a disconnect and someone reading the code has to find the definition of the routes elsewhere. It makes the code harder to understand and reason about. This makes refactoring harder as well.

Possible Solution

Use decorators inside of the controller to assign route information to the implementations (see express-decorators) and use config/routes.js to change the order that controllers are added to the server/init decorated controllers.

@controller('/users')
class Users {
  @get('/')
  listAll(req, res) {
    // return all users
  }
}

Then in the config/routes.js you could instantiate the decorated controller.

UserController.setupRoutes(this);

This could be built in, or possibly as a separate module (might not need to be a plugin).

If this is built in and the way to define routes, the routes config might just be an array or controller names, e.g.

export default [
  'users',
  'posts'
];

Issues/Drawbacks

Decorators are not stable yet (but close).

Caching addon

Provides a mixin to apply to Actions that lets you specify caching strategies declaratively for that action.

Fix record serialization errors

This may be an issue with the ember-help-wanted-backend setup I have here, but I'm using the latest code from #97 and latest default blueprints, so I don't think it is ember-learn/ember-help-wanted-backend#5

From what it looks like, this is a Denali issue, not an ORM adapter issue. It was time for me to get off 5-10 min ago, so putting this here in case someone else wants to fix it for me ;-) The above PR should have everything needed to replicate this error ...

[2016-09-28T00:06:30.133Z] ERROR - AssertionError: Attempted to serialize a record (<Issue:-new->) without an id, but the JSON-API spec requires all resources to have an id.
    at Function.renderRecord (./denali/lib/data/serializers/json-api.js:178:5)
    at ./denali/lib/data/serializers/json-api.js:93:21
    at Array.map (native)
    at Function.renderPrimaryArray (./denali/lib/data/serializers/json-api.js:91:31)
    at Function.renderPrimary (./denali/lib/data/serializers/json-api.js:70:12)
    at Function.serialize (./denali/lib/data/serializers/json-api.js:49:10)
    at ListIssues.render (./tmp/denali/lib/runtime/action.js:189:34)

Background & scheduled jobs

The framework should provide a top level abstraction similar to ActiveJob for Rails, where different job backend can plug into the same public API.

Auth addon

Need a cohesive story for auth. Should be simple out of the box, and could serve as a good test case / example addon

Initial linting has errors & security vulnerabilities unclear

iradchenko app (master)$ denali server
Linting failed:

/Users/iradchenko/battleground/app/config/environment.js
✖ 4 problems (4 errors, 0 warnings)


/Users/iradchenko/battleground/app/config/environment.js
  1:16  error  Missing JSDoc comment          require-jsdoc
  4:13  error  Unexpected use of process.env  no-process-env

/Users/iradchenko/battleground/app/config/middleware.js
  1:16  error  Missing JSDoc comment  require-jsdoc

/Users/iradchenko/battleground/app/config/routes.js
  1:16  error  Missing JSDoc comment  require-jsdoc

✖ 4 problems (4 errors, 0 warnings)

Build completed in 0.281s
[2016-07-30T00:18:30.653Z] INFO - [email protected] server up on port 3000
WARNING: Some packages in your package.json may have security vulnerabilities:
[object Object] 0 [object Object],[object Object],[object Object],[object Object]
[object Object] 1 [object Object],[object Object],[object Object],[object Object]
[object Object] 2 [object Object],[object Object],[object Object],[object Object]
[object Object] 3 [object Object],[object Object],[object Object],[object Object]

I tried to debug the security issue, but as I mentioned I couldn't get normal debugging working.

Secure by default approach

It would be great if Denali's default stance was security, which users can opt-out from. Things like frameguarding, CSP, etc should be turned on by default, with clear paths to disable for users who want to opt out.

`denali --help` broken

iradchenko app (master)$ denali --help
usage: denali [command] [args]

Available commands:

/Users/iradchenko/battleground/app/node_modules/denali/lib/cli/commands/root.js:44
    let pad = Object.keys(commands).reduce((longest, name) => Math.max(longest, name.length), 0);
                     ^
TypeError: Cannot convert undefined or null to object
    at RootCommand.printHelp (/Users/iradchenko/battleground/app/node_modules/denali/lib/cli/commands/root.js:44:22)

Would debug more, but unsure of how to debug denali. node debug which denali <command> doesn't seem to work. Neither do console logs..

Support adding blueprints via addon

Register addon blueprints/<name> as a blueprint callable by denali g <name>.

This is currently a blocker for pulling out the Mailer as an addon.

Setup ORM layer to default to snake_case pluralized table names

per our Gitter discussion, we want to have the default for table names be the following:

  • model name of issue -> table name issues
  • model name (BlogPost) -> table name blog_posts

This should be overridable at the model level ( @davewasmer do we want to add a method call of some kind at the ApplicationModel level to allow overriding this across the board if needed? )

Per-action verbose logging

Setting verbose = true on an action should enable detailed logging for requests that hit that action.

Support sockets

I think socket support is a must have for any ambitious framework, since it would probably be the deciding factor to use Denali for anyone needing them or thinking that they would in the future.

Also, it's an opportunity to shine, since socket code is usually more cluttered then router code, so if we can have a convention around sockets as well, all the better.

Update API docs

Audit codebase, ensure the inline doc blocks are up to date

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.