Wednesday, March 15, 2023
HomeJavascriptModel 3.0 launch notes | FoalTS

Model 3.0 launch notes | FoalTS


Banner

Model 3.0 of Foal is lastly there!

It has been a protracted work and I am excited to share with you the brand new options of the framework 🎉 . The upgrading information could be discovered right here.

Listed here are the brand new options and enhancements of model 3!

For these new to Foal, TypeORM is the default ORM utilized in all new tasks. However you should use every other ORM or question builder if you’d like, because the core framework is ORM impartial.

TypeORM v0.3 supplies better typing security and that is one thing that will likely be appreciated when shifting to the brand new model of Foal.

The model 0.3 of TypeORM has numerous adjustments in comparison with the model 0.2 although. Options such because the ormconfig.json file have been eliminated and features reminiscent of createConnection, getManager or getRepository have been deprecated.

Plenty of work has been completed to be sure that @foal/typeorm, new tasks generated by the CLI and examples within the documentation use model 0.3 of TypeORM with out counting on deprecated features or patterns.

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

Some elements of the framework have been simplified to require much less code and make it extra comprehensible.

Authentication​

The @UseSessions and @JWTRequired authentication hooks known as obscure features reminiscent of fetchUser, fetchUserWithPermissions to populate the ctx.person property. The actual position of those features was not clear and a newcomer to the framework may marvel what they had been for.

For this reason these features have been eliminated and changed by direct calls to database fashions.


@UseSessions({ person: fetchUser(Consumer) })
@JWTRequired({ person: fetchUserWithPermissions(Consumer) })


@UseSessions({ person: (id: quantity) => Consumer.findOneBy({ id }) })
@JWTRequired({ person: (id: quantity) => Consumer.findOneWithPermissionsBy({ id }) })

File add​

When importing recordsdata in a multipart/form-data request, it was not allowed to go optionally available fields. That is now attainable.

The interface of the @ValidateMultipartFormDataBody hook, renamed to @ParseAndValidateFiles to be extra comprehensible for individuals who do not know the HTTP protocol dealing with the add, has been simplified.

Examples with solely recordsdata


@ValidateMultipartFormDataBody({
recordsdata: {
profile: { required: true }
}
})


@ParseAndValidateFiles({
profile: { required: true }
})

Examples with recordsdata and fields


@ValidateMultipartFormDataBody({
recordsdata: {
profile: { required: true }
}
fields: {
description: { kind: 'string' }
}
})


@ParseAndValidateFiles(
{
profile: { required: true }
},


{
kind: 'object',
properties: {
description: { kind: 'string' }
},
required: ['description'],
additionalProperties: false
}
)

Database fashions​

Utilizing features like getRepository or getManager to control information in a database is just not essentially apparent to newcomers. It provides complexity that isn’t essential for small or medium sized tasks. Most frameworks want to make use of the Lively File sample for simplicity.

For this reason, from model 3 and to take note of that TypeORM v0.3 not makes use of a worldwide connection, the examples within the documentation and the turbines will lengthen all of the fashions from BaseEntity. In fact, it should nonetheless be attainable to make use of the features beneath if desired.


@Entity()
class Consumer {}

const person = getRepository(Consumer).create();
await getRepository(Consumer).save(person);


@Entity()
class Consumer extends BaseEntity {}

const person = new Consumer();
await person.save();

The usage of TypeScript varieties has been improved and a few elements of the framework guarantee higher kind security.

Validation with AJV​

Foal’s model makes use of ajv@8 which lets you bind a TypeScript kind with a JSON schema object. To do that, you possibly can import the generic kind JSONSchemaType to construct the interface of the schema object.

import { JSONSchemaType } from 'ajv';

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

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

File add​

In model 2, dealing with file uploads within the controller was tedious as a result of every type had been any. Beginning with model 3, it’s not essential to solid the categories to File or File[]:


const identify = ctx.request.physique.fields.identify;
const file = ctx.request.physique.recordsdata.avatar as File;
const recordsdata = ctx.request.physique.recordsdata.pictures as File[];


const identify = ctx.request.physique.identify;

const file = ctx.recordsdata.get('avatar')[0];

const recordsdata = ctx.recordsdata.get('pictures');

Authentication​

In model 2, the person possibility of @UseSessions and @JWTRequired anticipated a operate with this signature:

(id: string|quantity, providers: ServiceManager) => Promise<any>;

There was no method to guess and assure the kind of the person ID and the operate needed to verify and convert the kind itself if essential.

The returned kind was additionally very permissive (kind any) stopping us from detecting foolish errors reminiscent of confusion between null and undefined values.

In model 3, the hooks have been added a brand new userIdType choice to verify and convert the JavaScript kind if essential and pressure the TypeScript kind of the operate. The returned kind can be safer and corresponds to the kind of ctx.person which is not any however { [key : string] : any } | null.

Instance the place the ID is a string

@JWTRequired({
person: (id: string) => Consumer.findOneBy({ id });
userIdType: 'string',
})

Instance the place the ID is a quantity

@JWTRequired({
person: (id: quantity) => Consumer.findOneBy({ id });
userIdType: 'quantity',
})

By default, the worth of userIdType is a quantity, so we will merely write this:

@JWTRequired({
person: (id: quantity) => Consumer.findOneBy({ id });
})

GraphQL​

In model 2, GraphQL schemas had been of kind any. In model 3, they’re all primarily based on the GraphQLSchema interface.

Some elements have been modified to get nearer to the JS ecosystem requirements. Specifically:

Growth command​

The npm run develop has been renamed to npm run dev.

Configuration via setting variables​

When two values of the identical variable are supplied by a .env file and an setting variable, then the worth of the setting is used (the habits is much like that of the dotenv library).

null vs undefined values​

When the request has no session or the person is just not authenticated, the values of ctx.session and ctx.person are null and not undefined. This is smart from a semantic perspective, and it additionally simplifies the person project from the discover features of well-liked ORMs (Prisma, TypeORM, Mikro-ORM). All of them return null when no worth is discovered.

TypeORM is the default ORM used within the documentation examples and within the tasks generated by the CLI. However it’s fairly attainable to make use of one other ORM or question generator with Foal. For instance, the authentication system (with classes or JWT) makes no assumptions about database entry.

Some elements of the framework had been nonetheless a bit tied to TypeORM in model 2. Model 3 mounted this.

Shell scripts​

When working the foal generate script command, the generated script file not incorporates TypeORM code.

Permission system​

The @PermissionRequired possibility is not sure to TypeORM and can be utilized with any ctx.person that implements the IUserWithPermissions interface.

The @foal/aws-s3 bundle is now primarily based on model 3 of the AWS SDK. Because of this, the dimensions of the node_modules has been lowered by three.

All Foal’s dependencies have been upgraded. The framework can be examined on Node variations 16 and 18.

If the configuration file manufacturing.js explicitly returns undefined for a given key and the default.json file returns an outlined worth for this key, then the worth from the default.json file is returned by Config.get.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments