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
.