Falls version 3.0 is here

Version 3.0 of the Fall has finally arrived!

It’s been a long task and I’m excited to share the new features of the framework with you . The upgrade guide can be found here.

Here are the new features and improvements of version 3!

For those who don’t know it yet, Foal is a 5 year old full-featured Node.JS framework for building web applications. It is simple and easy to use based on TypeScript with very detailed documentation. And the best part: It’s tested by over 2,000 tests.

TypeORM v0.3 . full support of

TypeORM v0.3 offers more typing safety and this is something that will be appreciated as we move to the new version of the fall.

Version 0.3 of TypeORM however has a lot of changes compared to version 0.2. Features like ormconfig.json The file has been deleted and functions such as createConnection, getManager either getRepository is deprecated.

Much work has been done to ensure @foal/typeormNew projects generated by the CLI and the examples in the documentation use version 0.3 of TypeORM without relying on deprecated functions or patterns.

Specifically, the connection to the database is now managed by a single file src/db.ts that replaces the old ormconfig.json,

For those new to the fall, TypeORM is the default ORM used in all new projects. But you can use any other ORM or query builder if you want, as the core framework is ORM independent.

code simplified

Some parts of the framework have been simplified to require less code and make it more understandable.

certification

@UseSessions And @JWTRequired Obscure functions like authentication hooks are called fetchUser, fetchUserWithPermissions to populate ctx.user Property. The actual role of these functions was unclear and a newcomer to the framework may wonder what they were for.

This is why these functions have been deprecated and replaced by direct calls to the database model.

// Version 2
@UseSessions({ user: fetchUser(User) })
@JWTRequired({ user: fetchUserWithPermissions(User) })

// Version 3
@UseSessions({ user: (id: number) => User.findOneBy({ id }) })
@JWTRequired({ user: (id: number) => User.findOneWithPermissionsBy({ id }) })
enter fullscreen mode

exit fullscreen mode

file upload

a. while uploading files in multipart/form-data request, it was not allowed to pass optional fields. It’s possible now.

interface of @ValidateMultipartFormDataBody Hook, renamed . done @ParseAndValidateFiles Simplified to be more understandable to those who don’t know the HTTP protocol that handles uploads.

Example with only files

// Version 2
@ValidateMultipartFormDataBody({
  files: {
    profile: { required: true }
  }
})

// Version 3
@ParseAndValidateFiles({
  profile: { required: true }
})
enter fullscreen mode

exit fullscreen mode

Example with files and regions

// Version 2
@ValidateMultipartFormDataBody({
  files: {
    profile: { required: true }
  }
  fields: {
    description: { type: 'string' }
  }
})

// Version 3
@ParseAndValidateFiles(
  {
    profile: { required: true }
  },
  // The second parameter is optional
  // and is used to add fields. It expects an AJV object.
  {
    type: 'object',
    properties: {
      description: { type: 'string' }
    },
    required: ['description'],
    additionalProperties: false
  }
)
enter fullscreen mode

exit fullscreen mode

database model

using functions like getRepository either getManager Manipulating data in a database is not a must for newcomers. This adds complexity that is not necessary for small or medium sized projects. Most frameworks prefer to use the Active Record pattern for simplicity.

That is why, from version 3 and to take into account that TypeORM v0.3 no longer uses global connections, the examples in the documentation and generators will extend all models BaseEntity, Of course, it would still be possible to use the functions below if desired.

// Version 2
@Entity()
class User {}

const user = getRepository(User).create();
await getRepository(User).save(user);

// Version 3
@Entity()
class User extends BaseEntity {}

const user = new User();
await user.save();
enter fullscreen mode

exit fullscreen mode

better typing

The use of TypeScript types has been improved and some parts of the framework ensure better type safety.

Verification with AJV

Uses fall version ajv@8 Which allows you to bind a TypeScript type with a JSON schema object. To do this, you can import the generic type JSONSchemaType To create an interface of a schema object.

import { JSONSchemaType } from 'ajv';

interface MyData {
  foo: number;
  bar?: string
}

const schema: JSONSchemaType<MyData> = {
  type: 'object',
  properties: {
    foo: { type: 'integer' },
    bar: { type: 'string', nullable: true }
  },
  required: ['foo'],
  additionalProperties: false
}
enter fullscreen mode

exit fullscreen mode

file upload

In version 2, handling file uploads in the controller was tedious as there were all kinds of any, Starting with version 3, there is no longer a need to cast types File either File[],

// Version 2
const name = ctx.request.body.fields.name;
const file = ctx.request.body.files.avatar as File;
const files = ctx.request.body.files.images as File[];

// After
const name = ctx.request.body.name;
// file is of type "File"
const file = ctx.files.get('avatar')[0];
// files is of type "Files"
const files = ctx.files.get('images');
enter fullscreen mode

exit fullscreen mode

certification

In version 2, user option of @UseSessions And @JWTRequired Expects a function with this signature:

(id: string|number, services: ServiceManager) => Promise<any>;
enter fullscreen mode

exit fullscreen mode

There was no way to infer and guarantee the type of the userid and the function itself had to check and convert the type if necessary.

The returned type was also very permissive (Type any) preventing us from detecting silly errors, such as confusion null And undefined value.

In version 3, hooks have been added a new userIdType Option to check and convert JavaScript type and bind TypeScript type of function if needed. The returned type is also type safe and matches the type ctx.user who is no longer any But { [key : string] : any } | null,

Example where id is a string

@JWTRequired({
  user: (id: string) => User.findOneBy({ id });
  userIdType: 'string',
})
enter fullscreen mode

exit fullscreen mode

Example where id is a number

@JWTRequired({
  user: (id: number) => User.findOneBy({ id });
  userIdType: 'number',
})
enter fullscreen mode

exit fullscreen mode

By default, the value of userIdType is a number, so we can simply write it as:

@JWTRequired({
  user: (id: number) => User.findOneBy({ id });
})
enter fullscreen mode

exit fullscreen mode

GraphQL

In version 2, GraphQL schema types were any, In version 3, they are all based on GraphQLSchema interface.

js ecosystem closer to standards

Some parts have been modified to come closer to JS ecosystem standards. especially:

development order

npm run develop has been renamed npm run dev,

Configuration via Environment Variables

When two values ​​of the same variable a . are provided by .env file and an environment variable, then the value of the environment is used (the behavior is similar to that of the dotenv library).

null Vs undefined values

When the request has no session or the user is not authenticated, the value of ctx.session And ctx.user Huh null and no more undefined, This makes sense from a semantic point of view, and it also simplifies user assignments find Functions of popular ORMs (Prisma, TypORM, Micro-ORM). they all return null When no value is found.

More open to other ORMs

TypeORM is the default ORM used in documentation examples and in projects generated by the CLI. But with Fall it is quite possible to use another ORM or query generator. For example, the authentication system (with session or JWT) does not make any assumptions about database access.

Some parts of the framework were still slightly tied to TypeORM in version 2. Version 3 fixed it.

shell script

while driving foal generate script command, the generated script file no longer contains the TypeORM code.

permission system

@PermissionRequired Option is no longer bound to TypeORM and can be used with any ctx.user one who applies IUserWithPermissions interface.

Small AWS S3 Package

@foal/aws-s3 The package is now based on version 3 of the AWS SDK. thanks for this, size node_modules reduced to three.

Dependency updates and node support latest versions

All the Falls dependencies have been upgraded. The framework is also tested on node versions 16 and 18.

some bug fixes

if configuration file production.js explicitly returns undefined for a given key and default.json file returns a defined value for this key, again the value default.json file is returned by Config.get,

Article originally published here.

Leave a Comment