npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

foxx_generator

v0.5.1

Published

Generate Foxx APIs using Statecharts and Domain Driven Design

Downloads

3

Readme

FoxxGenerator

FoxxGenerator is a declarative JavaScript framework that allows developers to describe the API in terms of the domain using statecharts. This declarative approach is based upon a combination of Richardson and Amundsen's design approach described in their book RESTful Web APIs, Eric Evans' ideas from his book domain driven design and the Harel's statecharts introduced in his paper Statecharts: A Visual Formalism For Complex Systems.

To create an API with FoxxGenerator, first draw a statechart that represents your API. In this statechart, your states can have one of the following types:

  • Entity: This state represents something that has an identity and an arbitrary number of (optionally nested) attributes.
  • Repository: A repository can store entities.
  • Service: A service can do something. What it can do is defined via a JavaScript function that you can define. A service does not have a state.

Connect these states with transitions. When you have modeled your statechart in a way that it can fulfill all your use cases, it is time to classify your transitions. For every transition you have to decide which of the following type it follows:

  • follow: This is a transition that you can just follow from one state to the next.
  • connect: This is a point of extension where you can create a transition at runtime. In order to be able to follow this transition, you have to add a follow transition as well.
  • disconnect: With this transition you can remove a transition created with connect.
  • modify: This is a transition that can only be created from an entity to itself. It is used to modify the state of this entity.

You can now translate this annotated statechart into the DSL of FoxxGenerator to create your API.

Setting up a Foxx application with FoxxGenerator.

First, create a Foxx application as described in Foxx's manual. In the folder of your Foxx app, you can now install FoxxGenerator with npm install foxx_generator. In the same way you would add a controller to your Foxx application, you can now add a FoxxGenerator to your application: In the file that would normally contain your FoxxController, add the following:

var FoxxGenerator = require('foxx_generator').Generator,
  Joi = require('joi'),
  generator;

generator = new FoxxGenerator('name_of_your_app', {
  // To learn more about media types, see below
  mediaType: 'application/vnd.siren+json',
  applicationContext: applicationContext,
});

// Insert transition definitions here

// Insert states here

generator.generate();

For more information on how to choose a media type, see the section about Media types. Now you can define the transitions you used in your statechart and then add the states and the transitions between them.

Defining the transitions

Every transition needs the following attributes:

  • A name for the transition that you can use when you want to add a transition of this type.
  • type: One of the types described above.
  • to: Is the target of this transition one or more states? For a connect transition this for example determines if you can only connect one state to it or more than that. Acceptable values are one and many.

You can also add a documentation block (a JavaScript comment starting with /**) that will be used for the documentation. The first line should be a short summary, all other lines will be used for a long description. An example for that would be the following transition definition:

/** Show details for a particular item
 * 
 * Show all information about this particular item.
 */
generator.defineTransition('showDetail', {
  type: 'follow',
  to: 'one'
});

For a connect and disconnect transition you additionally have to determine which follow transition can be used to follow the created transition. This is done with as and the name of the transition.

You can also add parameters to the transition, if in the transition process you need additional information from the user of the API. Each of the parameters needs to be a value object defined with Joi. For example:

/** Modify the title of the entity
 *
 */
generator.defineTransition('changeTitle', {
  type: 'modify',
  to: 'one',

  parameters: {
    title: Joi.string()
  }
});

You can also define a condition for a transition. This is a JavaScript function that takes the parameters of the HTTP request as its argument and returns either true or false. If it is true, the transition can be executed. If it is false, the transition can not be executed and the link to execute it will be hidden from the representation. This can for example be used for user authorization.

Adding states and transitions

Now you can add states and transitions to your API. Every state has a name, a type and a number of outgoing transitions. The type is one of the above described ones – either entity, repository or service. Every transition needs information about where it leads to and via which transition type. The transition type needs to be defined as described above. Simple example:

generator.addState('ideas', {
  type: 'repository',
  contains: 'idea',

  transitions: [
    { to: 'idea', via: 'showDetail' }
  ]
});

Some states take additional information: Entities need to know which repository they are contained in (via containedIn) and repositories need to know which entities they contain (via contains).

States can also have a superstate. This can be done by providing superstate with the name of the state that should be the superstate as a string. The superstate is provided to the service via a third parameter in its action. It is an object that has a key called superstate where the value depends on the superstate's type:

  • If the superstate is an entity, it has a key entity where the value is the entity and a key repository which is the Foxx.Repository in which the entity is saved.
  • If the superstate is a repository, it has a key repository which contains the Foxx.Repository.

Entity

An entity can be parameterized (by setting its attribute parameterized to true) which means that there is not only one state of that type, but there can be an arbitrary amount – each of them is identified by a parameter. This is usually the case with entities that are stored in a repository.

It also takes an object of attributes which describe the representation of the entity. Each of the attributes needs to be a value object defined with Joi.

Example for an entity:

generator.addState('idea', {
  type: 'entity',
  parameterized: true,
  containedIn: 'ideas',

  attributes: {
    description: Joi.string().required(),
    title: Joi.string().required()
  },

  transitions: [
    { to: 'idea', via: 'relatedIdea' }
  ]
});

Service

A service needs to describe what it does, this is done with an action which is a function that takes a request and a response in the same way that a FoxxController route does. The default HTTP verb for a service is a post, it can be changed by setting the verb. Example:

generator.addState('title', {
  type: 'service',
  verb: 'get',

  action: function (req, res) {
    var entity = req.params('entity');
    res.json({ title: entity.get('title') });
  }
});

Media types

FoxxGenerator currently only supports siren which is a media type without application semantics. Use the media type application/vnd.siren+json. We plan to support HAL with an extension for forms in the near future.

Interactive Documentation

During your development, FoxxGenerator will generate an interactive documentation alongside the API. You can use this in an iterative development style to check after each step if the API is as you expected it to be. The documentation allows you to try out each of the generated endpoints. The API documentation can be found in the admin interface of ArangoDB and looks a little like this:

Overview

If you click on one of the routes, you can try it out:

Try it out

Examples

  • An example for a Siren API generated with FoxxGenerator can be found here

Linting

To check the project for linting errors, run npm run jshint.