foal

Full-featured Node.js framework 🚀

MIT License

Downloads
33.1K
Stars
1.9K
Committers
64
foal -

Published by LoicPoullain over 4 years ago

Features

  • Make JWTRequired and TokenRequired work with TypeORM and MongoDB (fetchMongoDBUser) (issue: #548) (PR: #701)
  • Request body and path parameters are now also passed as third and second arguments to the controller methods (issue: #507) (PR: #705)
  • Add HttpResponseTooManyRequests (issue: #664) (PR: #709)
  • Support custom type for ctx.state (issue: #711) (PR: #717)
  • [Bug] Make forceDownload option work on all browsers (PR: #722)

CLI

This version also takes care of closing a lot of pending issues.

  • [CLI] [Internal] Refactor the CLI to add new features in the future (issue: #577) (PR: #712)
  • [CLI] [Bug] Fix error displayed when running foal g vscode-config (issue: #694) (PR: #714).
  • [CLI] Support subdirectories in g service|controller (ex: foal g controller api/products --register) (issue: #368) (PR: #714)
  • [CLI] [Bug fix] Frontend projects attached to Foal with foal connect on Windows now can build on unix systems (issue: #562) (PR: #703)
  • [CLI] [Bug fix] Fix yarn installation failure on Node 8 (issue: #706) (PR: #705)
  • [CLI] [Bug fix] Scripts generated in a Mongoose project uses Mongoose (issue: #362) (PR: #715)
  • [CLI] Support --auth flag in foal g rest-api (issue: #366) (PR: #716)

Contributors

@matt-harvey
@kingdun3284
@AminTaghikhani

foal -

Published by LoicPoullain over 4 years ago

Features

This patch fixes type issues introduced in v1.8.0

  • Remove mongoose types (issue: #687) (PR: #688).
  • Remove "@types/express-serve-static-core" and define own Request interface (issue: #686) (PR: #690)
foal -

Published by LoicPoullain over 4 years ago

Features

  • Allow to inject interfaces and generic classes (such as TypeORM entities) (issues: #598, #627) (PR: #675).
  • ServiceManager.set returns itself (PR: #675).
  • Support service initialization (boot method) (issues: #628) (PR: #678)
  • Base64-encoding option for JWT secrets (issues: #523) (PR: #677)
  • UserWithPermissions extends BaseEntity (issue: #656) (PR: #682)
  • UserWithPermissions has a static method to get all users with a given permission (issue: #637) (PR: #682)
  • Fix recurring bugs with the types of @types/express (issue: #683) (PR: #685).

Dependencies

foal -

Published by LoicPoullain over 4 years ago

  • Fix multipart fields validation (#672)
foal -

Published by LoicPoullain over 4 years ago

Features

  • [Config] Ajv: support the option allErrors (issue: #633) (PR: #642)
  • [Config] Add an option not to log errors (issue: #612) (PR: #644)
  • [Storage] Add isFileDoesNotExist function (#657).
  • Enhance Config to support type and value checking. More detailed errors (issue: #496) (PR: #641)
  • Validate multipart/formdata requests to facilitate file uploads (issue: #560) (PR: #651)

Dependencies

foal - v1.6.0

Published by LoicPoullain over 4 years ago

Features

  • Support local and Cloud storage (fs and AWS S3) (issues: #604, #421) (PR: #611)
  • Allow to inject custom instances into the DI system (PR: #599)
  • Fix foal generate controller —register bug (issue: #606) (PR: #619)
  • [CLI] Clean the build directory before building the files (issue: #607) (PR: #621)
  • [Internal] Update GraphQL version and modify tsconfig (issue: #614) (PR: #623, #624)
  • Better stream error handling (PR: #611)

Deprecation

The function createHttpResponseFile is deprecated. Prefer to use Disk.createHttpResponse instead: https://foalts.gitbook.io/docs/topic-guides/file-system/upload-and-download-files#file-downloads

How to upgrade

npm update @foal/core # and all the other packages you use

Additionally, you can update your package.json like this.

Contributors

@jeredmasters

Dependencies

foal - v1.5.0

Published by LoicPoullain almost 5 years ago

Features

  • [Social auth] Add Github and LinkedIn providers (issue: #125) (PR: #591)
  • [CLI] Set default CSRF protection for sessions in the configuration (PR: #594).
  • Support the 'none' option for SameSite cookie attribute (PR: #594).
  • Be able to customize the global exception handler (issue: #370) (PR: #595)
  • Be able to increase the request body size limit (issue: #596) (PR: #597)
  • [Internal] Compile Foal's packages with the option noImplicitAny: true (PR: #600)
  • Remove type-graphql dependency introduced by mistake in v1.3.1 (PR: #608)
  • [CLI] Remove wrong npm naming control (PR: #610)

Dependencies

foal -

Published by LoicPoullain almost 5 years ago

There is no version v1.4.0. Please refer to version 1.5.0

foal -

Published by LoicPoullain almost 5 years ago

  • [Social Auth] [Bug] Improve social errors (issue: #582) (PR: #584)
foal -

Published by LoicPoullain almost 5 years ago

Features

  • Migrate to TypeScript version 3 (PR: #557) (breaking change).
  • Fix the unknown issue when building @foal/typestack (PR: #557).
  • Accept null as GraphQL query variables (PR: #553).
  • [CLI] Add --no-git and --no-install options to createapp (PR: #554).
  • [CLI] Stop createapp my-app if the directory my-app already exists (PR: #554).
  • [CLI] Fix bug: the CLI help is displayed unexpectedly (PR: #554).
  • [CLI] Generate new projects with ESLint instead of TSLint (issue: #555) (PR: #561) (big thanks to @fer22f)
  • [Social Auth] Add Facebook and Google providers (issue: #125) (PR: #563)
  • Upgrade sub-dependencies (PR: #578).

Breaking change

Due to a compatibility issue with class-transformer, Foal TS does not support TypeScript 2 anymore. Version 3.5 or higher is recommended.

Contributors

@firesharker
@fer22f

Dependencies

foal -

Published by LoicPoullain about 5 years ago

  • Add TypeStack unserialization and validation hooks (issue: #460) (PR: #542).
  • Support AppController.init to initialize the application (issue: #517) (PR: #544)
  • Support ExpressOptions.expressInstance in createApp(PR: #547)
  • Add community chat link in npm packages (PR: #541).
  • Remove Mongoose warning logs when creating a new project with foal createapp (PR: #541).
foal - v1.1.1

Published by LoicPoullain about 5 years ago

  • Fixes incorrect configuration for loggerFormat: none.
foal - v1.1.0

Published by LoicPoullain about 5 years ago

Features

  • HTTP Request Logger: Support the "none" option (issue: #475) (PR: #482).
  • Prettify the "500 error page" in development (issue: #479) (PR: #487).
  • Be able to extend Swagger UI options (issue: #486) (PR: #495).
  • [CLI] Set default TS version to 3.5 in new projects (foal createapp) (issue: #528) (PR: #531)
  • [CLI] Handle promise rejections in main (issue: #534) (PR: #535)
  • [Sessions][Auth] Support MongoDB as session storage (issue: #474) (PR: #513).
  • Support Nuxt.js and post Express middlewares (issue: #502) (PR: #536)
  • Support AJV "nullable" option (issue: #532) (PR: #537).

Contributors

@yaaminu
@kingdun3284
@amylily1011

foal - Fix small inconsistencies and bugs in v1.0.0

Published by LoicPoullain about 5 years ago

Content

  • foal g sub-app should not generate a sub sub-apps directory by default.
  • The configuration files generated with foal createapp --mongodb should not contain TypeORM options.
  • [Bug] Just like setCsrfToken, @CsrfTokenRequired should use the configuration key settings.csrf.cookie.name if it has a value.
  • [Bug] Make foal generate not fail if index.ts does not exist (PR: #484).
  • [Bug] Fix 500 errors on invalid JSON (issue: #457) (PR: #483)
  • [CLI] Add missing doc in command
foal - Version 1.0.0

Published by LoicPoullain over 5 years ago

What's new?

Finally the version 1 of FoalTs is out! This means that from now on:

  • the architecture of the framework is stable,
  • and features are production-ready.

This new version comes with hundreds of new lines of documentation and offers many new features:

  • The session authentication system has been refactored so that we can build any kind of apps (API, SPA+API, Mobile+API, Regular Web Apps) without the difficulties that we usually have to deal with with sessions (SPA, hot reloading, serverless deployments, etc)
  • VSCode debugger can be used when running unit or e2e tests.
  • New functions allow us to generate tokens when we need to (password reset, ).
  • Hooks can be merged into one single.
  • All Express-compatible template engines are now supported.
  • We can generate OpenAPI spec from the built-in hooks (JWTRequired, ValidateBody, TokenRequired, etc).
  • Hooks can access controller properties facilitating code reuse with inheritance.

Features (formal)

  • Be able to run unit & e2e tests with VSCode debugger (issue: #386) (PR: #444).
  • Infer OpenAPI specification from built-in hooks (ValidateXXX, JWTRequired, etc) (issues: #423, #424) (PR: #454)
  • Refactor the session system and introduce the authentication tokens (issue: #451) (PR: #456).
  • Have functions to generate and verify tokens (issue: #464) (PR: #456).
  • Be able to group multiple hooks into one (issue: #446) (PR: #453)
  • Implement the changes of version 1.0.0 (issue: #431) (PRs: #452, #465).
  • Make the hooks and open api decorators have access to the controller instance (issue: #459) (PR: #466)
  • Support Express template engines (issue: #445) (PR: #465)
  • Simplify hook post functions (PR: #466)

How to Upgrade to Version 1

Depending on your application, upgrading your code to version 1 should take between 15 minutes and 1 hour. Most applications are only concerned by a limited number of the points mentioned below.. As we are now on version 1, this the last major upgrade that you'll face.

If you have difficulties to upgrade to version 1, feel free to open an issue. I'll be happy to help!

Feel free to open an issue, if you have trouble upgrading to version 1. I'll be happy to help!

Mandatory

Don't be afraid.

npm install @foal/core@1 # and @foal/typeorm@1, @foal/jwt@1, etc. if it applies.
  1. The function encryptPassword has been renamed to hashPassword.

  2. The configuration key settings.staticUrl has been renamed to settings.staticPath.

    If you created your project with foal createapp <name>, open config/default.json and rename the key as follows:

    {
      "settings": {
        "staticPath": "public/"
        ...
      }
      ...
    }
    

    If you created your project with foal createapp <name> --yaml, open config/default.yml and rename the key as follows:

    settings:
      staticPath: public/
      ...
    ...
    
  3. If you use Server-Side Rendering, the function render now returns a Promise<HttpResponseOK> instead of an HttpResponseOK object. In most cases, it does not change anything to your code. The below example still work in version 1.

    class ViewController {
    
      @Get('/')
      index() {
        return render('./templates/index.html', { name: 'Hello!' }, __dirname)
      }
    
    }
    

    If you use @foal/ejs, uninstall the package and install directly ejs instead.

    npm uninstall @foal/ejs
    npm install ejs
    

    Then specify the name of the template engine in your configuration.

    Example with config/default.json

    {
      "settings": {
        "templateEngine": "ejs"
        ...
      }
      ...
    }
    

    Example with config/default.yml

    settings:
      templateEngine: "ejs"
      ...
    ...
    
  4. If you use cookies, the maxAge directive is now the number of seconds until the cookie expires (it was previously the number of milliseconds).

    // Before
    const response = new HttpResponseOK();
    response.setCookie('my-cookie-name', 'my-cookie-value', { maxAge: 60000 })
    
    // After
    const response = new HttpResponseOK();
    response.setCookie('my-cookie-name', 'my-cookie-value', { maxAge: 60 })
    
  5. If you provide your own express instance to createApp, the createApp function now accepts only two parameters.

    // Before
    const app = createApp(AppController, { /* ... */ }, myExpressApp);
    
    // After
    const app = createApp(AppController, myExpressApp);
    
  6. If you use hook post functions (which the case if you enabled CORS), their interface has been simplified. From now on, they only accept one parameter: the response object.

    CORS example

    // Before
    @Hook(() => (ctx, services, response) => {
      response.setHeader('Access-Control-Allow-Origin', '*');
    })
    export class ApiController {
      // ...
    }
    
    // After
    @Hook(() => response => {
      response.setHeader('Access-Control-Allow-Origin', '*');
    })
    export class ApiController {
      // ...
    }
    
  7. If you call directly the functions getApiComponents or getApiCompleteOperation (very unlikely), they now accept 2-3 parameters:

    // Before
    getApiComponents(Foobar);
    getApiComponents(Foobar, 'foo');
    
    // After
    getApiComponents(Foobar, new Foobar());
    getApiComponents(Foobar, new Foobar(), 'foo');
    
  8. If you use the hooks @ValidateBody, @ValidateQuery, @ValidateParams, @ValidateCookies, their HTTP responses are now more detailed.

    Example of HTTP response body for @ValidateParams

    // Before
    [
      // ...
    ]
    
    // After
    {
      "pathParams": [
        // ...
      ]
    }
    
  9. If you use sessions or authentication with sessions (@LoginRequired, @LoginOptional), go to the appendix Sessions below.

  10. If you use cookies and the CSRF protection,
    go to the appendix CSRF below.

Recommended

Previous versions of FoalTS used a ormconfig.json or ormcofing.yml file to specify the database credentials and the configuration of TypeORM.

However, this had some disadvantages:

  • It was difficult to provide database credentials using environment variables. We were stuck with names such as TYPEORM_USERNAME or TYPEORM_PASSWORD while most cloud providers use a different naming: DATABASE_PASSWORD, RDS_USERNAME, etc.
  • It was difficult to use a different database per environment. For example, it is very common to use different databases for development and testing. When running tests, we usually delete all existing data in the database, while when we run the server under development, we want the data from the last launch to be back.

This is why new versions of FoalTS use an ormconfig.js file along with the Config class (see example below). In this way, we can configure different configurations per environment (with config/ files) and use custom environment variable in ormconfig.js (RDS_USERNAME, etc).

I recommend that you migrate to this new configuration because it is used by default in new projects and in the new documentation.

In addition, new projects generated by FoalTS will not use the synchronize option by default. This option recreated the database schema each time the application was launched. This is very convenient during prototyping because we don't need to create and run migrations every time we modify a model. However, this use is considered unsafe and can erase data from the database by mistake (which we do NOT want in production).

This is why new projects disable this option by default (except during testing). As a replacement, developpers must generate and run migrations each time an entity is modified. It is a little annoying but more secure. The get started tutorials will explain how migrations work and how to use them.

Example with SQLite

ormconfig.js (it replaces ormconfig.js and ormconfig.yml)

const { Config } = require('@foal/core');

module.exports = {
  type: "sqlite",
  database: Config.get('database.database'),
  dropSchema: Config.get('database.dropSchema', false),
  entities: ["build/app/**/*.entity.js"],
  migrations: ["build/migrations/*.js"],
  cli: {
    migrationsDir: "src/migrations"
  },
  synchronize: Config.get('database.synchronize', false)
}

config/default.yml

port: 3001

settings:
  ...

database:
  database: './db.sqlite3'

config/default.json

{
  "port": 3001,
  "settings": {
    ...
  },
  "database": {
    "database": "./db.sqlite3"
  }
}

config/test.yml

database:
  database: './test_db.sqlite3'
  dropSchema: true
  synchronize: true

config/test.json

{
  "database": {
    "database": "./test_db.sqlite3",
    "dropSchema": true,
    "synchronize": true
  }
}

Note: the tests generated by foal g rest-api assume that you use this new configuration.

Optional

  1. If you have been using JWT so far to manage authentication and find it difficult, then take a look at the new Session Tokens.

  2. If you do not use Permissions or Groups, i.e your class User does not extend UserWithPermissions, you can remove the shell scripts create-perm.ts and create-group.ts from the directory src/scripts.

  3. If you do not use Server-Side Rendering with EJS, you can uninstall the @foal/ejs package from your application.

    npm uninstall @foal/ejs
    
  4. HttpResponse.setHeader and HttpResponse.setCookie now returns this. So the below example can be refactored as follows to reduce the amount of code.

    class ApiController {
    
      @Get('/products')
      readProducts() {
        // Before
        const response = new HttpResponseOK();
        response.setHeader('XXX', 'my header value');
        response.setCookie('XXX', 'my cookie value');
        return response;
    
        // Possible refactoring after
        return new HttpResponseOK()
          .setHeader('XXX', 'my header value')
          .setCookie('XXX', 'my cookie value');
      }
    
    }
    

Appendices

Sessions

In version 1, the session system has been redesigned to do less magic and to allow developpers to build any kind of applications using sessions (SPA, Mobile, Regular Web Applications).

  1. Remove the ExpressJS store from your file src/index.ts.

    Before

    // ...
    import * as sqliteStoreFactory from 'connect-sqlite3';
    // ...
    
    async function main() {
      // ...
    
      const app = createApp(AppController, {
        store: session => new (sqliteStoreFactory(session))({ db: 'db.sqlite3' })
      });
    
      // ...
    }
    
    main();
    

    After

    // ...
    
    async function main() {
      // ...
    
      const app = createApp(AppController);
    
      // ...
    }
    
    main();
    
    npm uninstall connect-sqlite3
    

    In the new version, FoalTS only supports Redis and SQL databases for session storage. If you need more option, feel free to open an issue on Github.

  2. Replace @LoginRequired({ user: xxx }) with @TokenRequired({ user: xxx, store: TypeORMStore, cookie: true }).

    Before

    import { LoginRequired } from '@foal/core';
    import { fetchUser } from '@foal/typeorm';
    
    import { User } from '../entities';
    
    @LoginRequired({ user: fetchUser(User) })
    export class ApiController {
      // ...
    }
    

    After

    import { TokenRequired, TypeORMStore } from '@foal/core';
    import { fetchUser } from '@foal/typeorm';
    
    import { User } from '../entities';
    
    @TokenRequired({
      store: TypeORMStore,
      user: fetchUser(User),
      cookie: true
    })
    export class ApiController {
      // ...
    }
    
  3. In the same way, replace @LoginOptional({ user: xxx }) with @TokenOptional({ user: xxx, store: TypeORMStore, cookie: true }).

  4. Open config/default.json (or config/default.yml) and replace the session settings with the following:

    Before

    {
      "settings": {
        ...
        "session": {	
          "cookie": {	
            "path": "/"	
          },	
          "resave": false,	
          "saveUninitialized": false,	
          "secret": "my-secret"	
        }
      },
      ...
    }
    

    After

    {
      "settings": {
        ...
        "session": {	
          "cookie": {	
            "path": "/"	
          },	
          "secret": "my-secret"	
        }
      },
      ...
    }
    
  5. Open config/production.json (or config/production.yml) and replace the session settings with the following:

    Before

    {	
      "settings": {	
        "session": {	
          "cookie": {	
            "httpOnly": true,	
            "maxAge": 3600000,	
            "sameSite": "lax",	
            "secure": true	
          },	
          "name": "id"	
        }	
      }	
    }
    

    After

    {	
      "settings": {	
        "session": {	
          "cookie": {	
            "httpOnly": true,	
            "maxAge": 3600,	
            "sameSite": "lax",	
            "secure": true,
            "name": "id"	
          }
        }	
      }	
    }
    
    
  6. If you use ctx.request.session, update your code as follows:

    // Before
    const x = ctx.request.session.x;
    ctx.request.session.y = 1;
    
    // After
    const x = ctx.session.get('x');
    ctx.session.set('y', 1);
    
  7. Update your "login and logout controller" as follows:

    Before

    export class AuthController {
    
      @Post('/login')
      // ...
      async login(ctx: Context) {
        // ...
    
        logIn(ctx, user);
    
        return new HttpResponseRedirect('/');
      }
    
      @Get('/logout')
      logout(ctx) {
        logOut(ctx);
        return new HttpResponseRedirect('/signin');
      }
    
    }
    

    After

    import { Context, dependency, Post, removeSessionCookie, Session, setSessionCookie, TokenRequired } from '@foal/core';
    import { TypeORMStore } from '@foal/typeorm';
    
    export class AuthController {
      @dependency
      store: TypeORMStore;
    
      @Post('/login')
      // ...
      async login(ctx: Context) {
        // ...
    
        const session = await this.store.createAndSaveSessionFromUser(user);
    
        const response = new HttpResponseRedirect('/');
        setSessionCookie(response, session.getToken());
        return new HttpResponseRedirect('/');
      }
    
      @Post('/logout')
      @TokenRequired({
        store: TypeORMStore,
        cookie: true,
        extendLifeTimeOrUpdate: false
      })
      async logout(ctx: Context<any, Session>) {
        await this.store.destroy(ctx.session.sessionID);
        const response = new HttpResponseRedirect('/login');
        removeSessionCookie(response);
        return response;
      }
    
    }
    

CSRF

  1. Install the package @foal/csrf.

    npm install @foal/csrf
    
  2. If you use sessions, add the hook @CsrfTokenRequired() after @TokenRequired(...)

    Example

    import { CsrfTokenRequired } from '@foal/csrf';
    
    @TokenRequired({
      cookie: true,
      /* ... */
    })
    @CsrfTokenRequired()
    export class ApiController {
      // ...
    }
    
  3. OR if you use double submit cookie technique, add the hook @CsrfTokenRequired({ doubleSubmitCookie: true }) on the protected routes.

    Example

    import { CsrfTokenRequired } from '@foal/csrf';
    
    // Ex: @JWTRequired()
    @CsrfTokenRequired({ doubleSubmitCookie: true })
    export class ApiController {
    
    }
    
  4. The CSRF configuration has changed from

    settings:
      csrf: true
    

    to

    settings:
      csrf:
        enabled: true
    
  5. Replace ctx.request.csrfToken() with getCsrfToken(ctx.session) if you use sessions or getCsrfToken() if you use double submit cookie technique.

    Before

    export class PageController {
    
      @Get('/home')
      home(ctx: Context) {
        return render(
          './templates/index.html',
          { csrfToken: ctx.request.csrfToken() }
          , __diname
        );
      }
    
    }
    

    After

    import { getCsrfToken } from '@foal/csrf';
    
    @TokenRequired(/* ... */) // Only if you use sessions
    export class PageController {
    
      @Get('/home')
      home(ctx: Context) {
        return render(
          './templates/index.html',
          { csrfToken: getCsrfToken(ctx.session) }
          , __diname
        );
      }
    
    }
    
foal - May Release

Published by LoicPoullain over 5 years ago

Features

  • Prevent name conflicts with "foal g rest-api" (PR: #426)
  • Support server-side authentication with Auth0 & AWS Cognito (be able to retrieve RSA public key from JWKS endpoint) (issues: #320, #405) (PR: #430)
  • Add GraphQL components to create HTTP GraphQL servers (issue: #427) (PR: #126)
  • Fix invalid environment variable conversion in Config (issue: #437) (PR: #438).

How to upgrade

npm install -g @foal/cli
npm update @foal/core # and other @foal/xxx if needed
foal - April Release

Published by LoicPoullain over 5 years ago

Features

  • Support OpenAPI & Swagger UI (issue: #276) (PR: #403)
  • Add the class HttpResponseMovedPermanently (PR: #403)
  • Fix case-sensitive headers in the @Log hook (issue: #409) (PR: #410)
  • Reduce the number of dependencies of the core package (19 indirect dependencies) (PR: #413)

How to upgrade

npm install -g @foal/cli
npm update @foal/core # and other @foal/xxx if needed
foal - March Release

Published by LoicPoullain over 5 years ago

Features

  • Update to v0.8 the message displayed with 500 errors (issue: #387).
  • Have a CLI command to generate secrets (issue: #365) (PR: #392).
  • [@foal/cli] New projects will use source maps when displaying error traceback upon unit and e2e testing (issue: #385) (PR: #391).
  • Support stateless CSRF protection using double submit cookie technique (issue: #363) (PR: #396).
  • Be able to specify a virtual path prefix for static files (issue: #382) (PR: #393).
  • Provide a class ConfigMock to mock the Config when it used as a service (issue: #367) (PR: #394).
  • Add a ValidateCookies hook (issue: #375) (PR: #398).
  • Support file uploads and downloads (issues: #374, #298)

How to upgrade

npm install -g @foal/cli
npm update # in your project

Contributors

@swanncastel
@LoicPoullain

foal -

Published by LoicPoullain over 5 years ago

Features

  • New projects created with the CLI will now use TypeScript 3.3 or greater by default (issue: #377) (PR: #379).
  • Add 1300 lines of doc comment in the code (PR: #373).

How to upgrade

npm install -g @foal/cli
npm update # in your project
foal -

Published by LoicPoullain over 5 years ago

Features

  • [@foal/cli] Set the default cookie path to / in config/ (issue: #357) (PR: #358)
Package Rankings
Top 1.86% on Npmjs.org
Top 8.17% on Proxy.golang.org
Badges
Extracted from project README
backers
Related Projects