Published by LoicPoullain over 5 years ago
Context.request
(issue: #318) (PR: #337).npm install -g @foal/cli
npm install @foal/[email protected] # and @foal/[email protected], @foal/[email protected], etc if relevant.
The new configuration system should be the only breaking change in the February release. Feel free to submit an issue if you are having trouble migrating.
New versions of Foal uses by default the port 3001 to not conflict with a running React server. You can still keep the port 3000 if you want.
Update all the Config.get
calls in your code:
// Before
Config.get('mongodb', 'uri');
Config.get('settings', 'staticUrl', 'public/') as string;
// After
Config.get('mongodb.uri');
Config.get<string>('settings.staticUrl', 'public/');
Before:
- mongodb.e2e.json
- mongodb.development.json
- settings.development.json
- settings.json
After:
- e2e.json
- development.json
- default.json
// ***********
// Before
// ***********
// mongodb.development.json
{
"uri": "my_uri"
}
// settings.development.json
{
"debug": true
}
// ***********
// After
// ***********
// development.json
{
"mongodb": {
"uri": "my_uri"
},
"settings": {
"debug": false
}
}
@foal/jwt
package, replace the env variables JWT_WHATEVER
with SETTINGS_JWT_WHATEVER
and update your config files as follows:// incorrect
{
"jwt": {
"secret": "xxx"
},
"settings": {
...
}
}
// correct
{
"settings": {
"jwt": {
"secret": "xxx"
},
...
}
}
The settings
section now encompasses all the configuration of the official Foal packages.
AJV_WHATEVER
with SETTINGS_AJV_WHATEVER
and update your config files as follows:// incorrect
{
"ajv": {
"coerceTypes": true
},
"settings": {
...
}
}
// correct
{
"settings": {
"ajv": {
"coerceTypes": true
},
...
}
}
The settings
section now encompasses all the configuration of the official Foal packages.
// Before
{
"sessionResave": false,
"sessionSaveUninitialized": false,
"sessionSecret": "my-secret",
"sessionCookieHttpOnly": true,
"sessionCookieMaxAge": 1000,
"sessionCookieSameSite": "lax",
"sessionCookieSecure": true,
"sessionName": "id"
}
// After
{
"settings": {
"session": {
"resave": false,
"saveUninitialized": false,
"secret": "my-secret",
"cookie": {
"httpOnly": true,
"maxAge": 3600000,
"sameSite": "lax",
"secure": true
},
"name": "id"
}
}
}
Here's are examples of config files using the new system:
You'll find more information here on how the new configuration system works.
Published by LoicPoullain almost 6 years ago
createapp
command (issue: #310) (PR: 309).foal run
as alias of foal run-script
(PR: #316).foal createapp
: prettify the outputs and auto initialize git repo (issue: #314) (PR #317).@jamesgeorge007
@LoicPoullain
Published by LoicPoullain almost 6 years ago
npm install -g @foal/cli
.{
...
"dependencies": {
"@foal/core": "~0.7.0",
"@foal/ejs": "~0.7.0",
"@foal/typeorm": "~0.7.0",
...
}
}
parsePassword
with encryptPassword(password, { legacy: true })
AuthenticateWithSessionAndCookie
(you might need to use the LoginOptional
hook in some situations)fetchUser
from @foal/typeorm
and replace @LoginRequired()
by @LoginRequired({ user: fetchUser(User) )}
AbstractUser
to UserWithPermissions
and import it from @foal/typeorm
EntityResourceCollection
, EmailAuthenticator
, emailSchema
, middleware
, Group
, Permission
and PermissionRequired
from @foal/typeorm
instead of @foal/core
.The purpose of this release is to make the code of FoalTS less complex, more readable and modular and to add the support of recent technologies (JWT). It introduces some changes and improvements listed below.
AuthenticationWithSessionAndCookie
and LoginRequired
hooks have been mergedIn previous versions of FoalTS, AuthenticationWithSessionAndCookie
and LoginRequired
were both required to authenticate and restrict access to authenticated users. They have been merged into one hook LoginRequired
for simplicity (and consistency with the JWTRequired
hook presented below). A new hook LoginOptional
has also been added in this version.
Old code:
import { AuthenticationWithSessionAndCookie, LoginRequired, Get } from '@foal/core';
...
@AuthenticationWithSessionAndCookie(User)
export class AppController {
@Get('/')
index(ctx) {
const name = ctx.user ? ctx.user.name : 'you';
return new HttpResponseOK(`Hello ${name}!`);
}
@Get('/home')
@LoginRequired({ redirect: '/' })
home(ctx) {
return new HttpResponseOK(`Hello ${ctx.user.name}!`);
}
}
New code:
import { LoginOptional, LoginRequired, Get } from '@foal/core';
import { fetchUser } from '@foal/typeorm';
...
export class AppController {
@Get('/')
@LoginOptional({ user: fetchUser(User) })
index(ctx) {
const name = ctx.user ? ctx.user.name : 'you';
return new HttpResponseOK(`Hello ${name}!`);
}
@Get('/home')
@LoginRequired({ redirect: '/', user: fetchUser(User) })
home(ctx) {
return new HttpResponseOK(`Hello ${ctx.user.name}!`);
}
}
JWTRequired
and JWTOptional
This release adds the support of JWT for authentication. The two new hooks JWTRequired
and JWTOptional
are similar to LoginRequired
and LoginOptional
.
Example:
import { Get, isInFile } from '@foal/core';
import { JWTRequired } from '@foal/jwt';
import { fetchUser } from '@foal/typeorm';
export class AppController {
@Get('/home')
@JWTRequired()
home(ctx) {
return new HttpResponseOK(`Hello ${ctx.user.name}!`);
}
}
export class AppController2 {
@Get('/home')
// With some options
@JWTRequired({ user: fetchUser(User), blackList: isInFile('./blacklist') }, { audience: 'foobar' })
home(ctx) {
return new HttpResponseOK(`Hello ${ctx.user.name}!`);
}
}
encryptPassword
and verifyPassword
You can now manage password encryption directly with the encryptPassword
and verifyPassword
functions.
Note: The parsePassword(password)
util has been removed. Use its equivalent with encryptPassword
: encryptPassword(password, { legacy: true })
.
In the previous versions of FoalTS, the sub-controllers' routes were registered after the controller routes. Then it was hard to display a custom 404 page when a route did not exist. In the example below, requesting /home
was returning a 404
instead of 200 - 'You are on the home page!'
export class ViewController {
@Get('/')
index() {
return new HttpResponseOK('Hello world');
}
@Get('/home')
home() {
return new HttpResponseOK('You are on the home page!');
}
}
export class AppController {
subControllers = [ ViewController ];
@Get('*')
notFound() {
return new HttpResponseNotFound('The page your are looking for does not exist');
}
}
This is now changed and this example returns a success on GET /home
.
@foal/typeorm
All TypeORM-dependent components have been moved to a separate package @foal/typeorm
.
These components are:
EmailUser
and EmailAuthenticator
(deprecated)emailSchema
(deprecated)Middleware
, RelationLoader
, middleware
, EntityResourceCollection
(deprecated)Group
, Permission
, UserWithPermissions
PermissionRequired
fetchUserWithPermissions
, fetchUser
This way developers can use another ORM/ODM if they want (Mongoose, Sequelize, etc)
User
class and the UserWithPermissions
entity (previously named AbstractUser
)The abstract class AbstractUser
has been renamed into UserWithPermissions
.
Because not all applications require permissions and groups, and a different ORM can be used instead of TypeORM, the User
class no longer needs to extend the class UserWithPermissions
.
The type of Context['user']
is now any
. You can force this type with a generic parameter: Context<User>
.
Due to their unnecessary complexity, some components have been deprecated and will be removed in further versions:
IAuthenticator
Strategy
, strategy
, LoginController
IResourceCollection
, CollectionParams
RestController
EmailUser
and EmailAuthenticator
emailSchema
Middleware
, RelationLoader
, middleware
, EntityResourceCollection
Here are some alternatives that you might consider:
encryptPassword
and verifyPassword
foal generate rest-api <name>
(coming in a next release in January 2019)ctx.request.csrfToken is not a function
when the CSRF protection is disabled (issue: #283) (PR: #284).AuthenticationWithSessionAndCookie
and LoginRequired
into LoginRequired
and LoginOptional
(issue: #286) (PR: #287)encryptPassword
and verifyPassword
to manage password encryption(issue: https://github.com/FoalTS/foal/issues/288) (PR: #300).EmailAuthenticator
, EmailSchema
, LoginController
, PermissionRequired
, AbstractUser
, Group
, Permission
, fetchUser
, fetchUserWithPermissions
, EntityResourceCollection
to the new package @foal/typeorm
(issue: #290) (PR: #293 ).AbstractUser
to UserWithPermissions
and simplify the definition of Context
(issue: https://github.com/FoalTS/foal/issues/291) (PR: #293)EmailUser
, EmailAuthenticator
, emailSchema
, Middleware
, RelationLoader
, middleware
, EntityResourceCollection
, IAuthenticator
, Strategy
, strategy
, LoginController
, IResourceCollection
, CollectionParams
and RestController
(issue: #288) (PR: #293, #295).@LoicPoullain
@rustamwin
Published by LoicPoullain almost 6 years ago
foal createapp
(https://github.com/FoalTS/foal/pull/270).Published by LoicPoullain almost 6 years ago
Published by LoicPoullain almost 6 years ago
HEAD
and OPTIONS
(https://github.com/FoalTS/foal/pull/262).Authenticate
to AuthenticateWithSessionAndCookie
(https://github.com/FoalTS/foal/pull/263).void | HttpResponse | HookPostFunction | Promise <void | HttpResponse | HookPostFunction>
and not any
anymore.@Hook(ctx => ctx.state.foo = 2)
, you to have update its definition as follows: @Hook(ctx => { ctx.state.foo = 2; })
Authenticate
is now named AuthenticateWithSessionAndCookie
.@LoicPoullain
@Jrfidellis
Published by LoicPoullain about 6 years ago
getAjvInstance
in LoginController
.Log
hook print information about the HTTP request (https://github.com/FoalTS/foal/pull/246) (breaking change).logIn
and logOut
utilities (https://github.com/FoalTS/foal/pull/247).HttpResponse
support headers and cookies (https://github.com/FoalTS/foal/pull/251).headers
of HttpResponse
is now private. You need to use the setHeader
, getHeader
and getHeaders
methods instead.Log
Hook is not the log function anymore but an options
object.
@Log('hello', console.error) // before
@Log('hello', { logFn: console.error }) // after
Published by LoicPoullain about 6 years ago
This release introduces numerous breaking changes. They are the fruit of several feedbacks and should be the last breaking changes of this version. v0.6.0
will come out soon!
isCommon
to test if a password is too common (issue: https://github.com/FoalTS/foal/issues/111) (https://github.com/FoalTS/foal/pull/229).strictPropertyInitialization
to false
in tsconfig.json
and remove the ts-ignore
s (https://github.com/FoalTS/foal/pull/234).ValidateParams
and ValidateHeaders
(https://github.com/FoalTS/foal/pull/236).@LoicPoullain
@Jrfidellis
npm update
.@foal/cli
: npm -g update @foal/cli
.Create a new file src/test.ts
with the content process.env.NODE_ENV = 'test';
. Then in your package.json
make the commands start:test
and start:test:w
start with mocha --file \"./lib/test.js\"
.
src/e2e
.supertest
: npm install --save-dev supertest
.package.json
by these ones: https://github.com/FoalTS/foal/blob/fd037498bde5798452a46f87b22ad4c456af64b1/packages/cli/src/generate/specs/app/package.json
e2e.ts
in src/
with this content: process.env.NODE_ENV = 'e2e'
Update your scripts following this pattern:
const argSchema = {
/* ... */
};
export function main(argv) {
const args = getCommandLineArguments(argv);
try {
validate(argSchema, args);
} catch (error) {
if (error instanceof ValidationError) {
error.content.forEach(err => {
console.log(`The command line arguments ${err.message}`);
});
return;
}
throw error;
}
/* ... */
}
// Replace this with:
export const schema = {
/* ... */
};
export function main(args) {
/* ... */
}
ValidateQuery
& ValidateBody
The hooks ValidateQuery
and ValidateBody
now use under the hood this configuration of Ajv:
{
coerceTypes: true, // change data type of data to match type keyword
removeAdditional: true, // remove additional properties
useDefaults: true, // replace missing properties and items with the values from corresponding default keyword
}
Module
, Controller
and Service
.@Controller()
export class MyController {
constructor(private myService1: MyService1, public myService2: MyService2) {}
}
// becomes:
export class MyController {
@dependency
private myService1: MyService1;
@dependency
myService2: MyService2;
}
RestController
s following this pattern:export class MyController extends RestController {
collectionClass = MyCollectionClass;
}
// becomes:
export class MyController extends RestController {
@dependency
collection: MyCollectionClass;
}
createService
or createController
.**.module.ts
into **.controller.ts
export AppModule implements IModule {
controllers = [
controller('/foo', Controller1)
];
subModules = [
subModule('/api', ApiModule)
];
}
// Replace this with:
export AppController {
subControllers = [
controller('/foo', Controller1),
controller('/api', ApiController)
];
}
sub-modules
to sub-apps
.src/index.ts
, import AppController
instead of AppModule
as it no longer exists.Published by LoicPoullain about 6 years ago
EntityResourceCollection
(https://github.com/FoalTS/foal/pull/196).create-user
, create-group
and create-perm
scripts (issue: https://github.com/FoalTS/foal/issues/162) (PR: https://github.com/FoalTS/foal/pull/197).foal run-script
feature (https://github.com/FoalTS/foal/pull/202).Update your local dependencies: npm update
.
Update globally @foal/cli
: npm -g update @foal/cli
.
The entity Group
now has a codeName
.
synchronize
set to true
in your ormconfig.json
then the database schema will automatically be updated.npm run build
npm run migration:generate -- -n add-codename-to-group
npm run build
npm run migration:run
Remove src/scripts/create-users.ts
and add the following scripts:
Remove the line "sessionCookieDomain": "localhost"
in config/settings.production.json
.
Published by LoicPoullain about 6 years ago
render
use template paths (https://github.com/FoalTS/foal/pull/184).src/migrations
(issue: https://github.com/FoalTS/foal/issues/175) (https://github.com/FoalTS/foal/issues/185).index.ts
when creating a file (https://github.com/FoalTS/foal/pull/186).Update your dependencies by running npm update
.
render
util// Before
import { readFileSync } from 'fs';
import { join } from 'path';
const login = readFileSync(join(__dirname, './templates/login.html'), 'utf8');
render(login, { csrfToken: ctx.request.csrfToken() });
// After
render('./templates/login.html', { csrfToken: ctx.request.csrfToken() }, __dirname);
migrations
directory (if it exists) to src
.tslint.json
and ormconfig.json
with:{
...
"linterOptions": {
"exclude": "src/migrations/*.ts"
}
}
{
...
"migrations": ["lib/migrations/*.js"],
"cli": {
"migrationsDir": "src/migrations"
},
}
Published by LoicPoullain about 6 years ago
copy
command work on Windows (hot fix).Published by LoicPoullain about 6 years ago
@foal/cli
: 901 -> 34) (issue https://github.com/FoalTS/foal/issues/174).test.ts
file (issue https://github.com/FoalTS/foal/issues/174).InitDB
and add a createConnection
in the main index.ts
file instead.copy
and to get rid of webpack
.tsconfig.json
and ormconfig.json
to use the correct paths.scripts/
directory into src
.require('**/*.html')
by fs
reads.lib/
directory.npm update
.InitDB
does not longer exist and you don't need to register your entities anymore. Remove the hook from your code and replace the content of src/index.ts
by this:// The imports ...
async function main() {
await createConnection();
const app = createApp(AppModule, {
store: session => new (sqliteStoreFactory(session))({ db: 'db.sqlite3' })
});
const httpServer = http.createServer(app);
const port = Config.get('settings', 'port', 3000);
httpServer.listen(port, () => {
console.log(`Listening on port ${port}...`);
});
}
main();
package.json
by this:{
"build": "tsc && copy-cli \"src/**/*.html\" lib",
"build:w": "tsc -w",
"start": "node ./lib/index.js",
"start:w": "supervisor -w ./lib --no-restart-on error ./lib/index.js",
"develop": "npm run build && concurrently \"npm run build:w\" \"npm run start:w\"",
"build:test": "tsc && copy-cli \"src/**/*.html\" lib",
"build:test:w": "tsc -w",
"start:test": "mocha \"./lib/**/*.spec.js\"",
"start:test:w": "mocha -w \"./lib/**/*.spec.js\"",
"test": "npm run build:test && concurrently \"npm run build:test:w\" \"npm run start:test:w\"",
"lint": "tslint -c tslint.json -p tsconfig.json",
"migration:generate": "ts-node ./node_modules/.bin/typeorm migration:generate",
"migration:run": "ts-node ./node_modules/.bin/typeorm migration:run",
"migration:revert": "ts-node ./node_modules/.bin/typeorm migration:revert"
}
tsconfig.json
and ormconfig.json
:// tsconfig
"outDir": "lib"
//ormconfig
"entities": ["lib/app/**/*.entity.js"],
scripts/
directory to src
.require('./foobar.html')
to fs.readFileSync(path.join(__dirname, './foobar.html'), 'utf8')
.Published by LoicPoullain about 6 years ago
Goal: Create complex REST API.
ISerializer
to IResourceCollection
and EntitySerializer
to EntityResourceCollection
(https://github.com/FoalTS/foal/pull/170).IResourceCollection
interface (https://github.com/FoalTS/foal/pull/172).User
entity and scripts/create-users
consistent (https://github.com/FoalTS/foal/pull/176).PermissionDenied
and ValidationError
in EntityCollection
s (https://github.com/FoalTS/foal/pull/173).allowedOperations
, loadedRelations
and middlewares
in EntityResourceCollection
(https://github.com/FoalTS/foal/pull/173).params.fields
in EntityResourceCollection
to restrict the returned representations (https://github.com/FoalTS/foal/pull/173).Published by LoicPoullain about 6 years ago
Goal: having an authentication and authorization system that work.
isHttpResponseXXX
(https://github.com/FoalTS/foal/pull/160).Authenticate
hook in generated apps (https://github.com/FoalTS/foal/pull/164).createController
util (https://github.com/FoalTS/foal/pull/166).LoginController
bug "get" of undefined
(https://github.com/FoalTS/foal/pull/166).PermissionRequired
.Published by LoicPoullain about 6 years ago
chai
from created apps. (https://github.com/FoalTS/foal/pull/155).Login
controllers (https://github.com/FoalTS/foal/pull/157).LoginRequired
.HookDecorator
to hook template.ValidateQuery
hook (https://github.com/FoalTS/foal/pull/158).bootstrap
from @foal/cli
(https://github.com/FoalTS/foal/pull/159).