- Packages Before and After Migration
- Relevant Stack
- Upgrade and Modifications to Configuration
- Config Changes
- Authentication Modifications
- Validation
- Client Validation
- Server Validation
feathers packages pre-migration
"@feathersjs/authentication": "^2.1.13",
"@feathersjs/authentication-jwt": "^2.0.7",
"@feathersjs/authentication-local": "^1.2.7",
"@feathersjs/client": "^3.7.8",
"@feathersjs/configuration": "^2.0.4",
"@feathersjs/errors": "^3.3.4",
"@feathersjs/express": "^1.2.7",
"@feathersjs/feathers": "^3.3.1",
"@feathersjs/socketio": "^3.2.7",
"@feathersjs/socketio-client": "^1.2.1"
ecosystem packages before
"feathers-authentication-hooks": "^0.3.1",
"feathers-blob": "^2.1.0",
"feathers-hooks-common": "^4.20.7",
"feathers-hooks-validate-joi": "^2.0.0",
"feathers-knex": "^5.0.5",
"feathers-objection": "^3.2.1",
"feathers-permissions": "^0.2.1",
"feathers-redux": "^3.0.0",
"feathers-reduxify-authentication": "^1.0.1"
updated feathers packages
"@feathersjs/authentication": "^4.3.0",
"@feathersjs/authentication-local": "^4.3.0",
"@feathersjs/authentication-oauth": "^4.3.0",
"@feathersjs/client": "^4.3.5",
"@feathersjs/configuration": "^4.3.0",
"@feathersjs/errors": "^4.3.0",
"@feathersjs/express": "^4.3.0",
"@feathersjs/feathers": "^4.3.0",
"@feathersjs/socketio": "^4.3.0",
"@feathersjs/socketio-client": "^4.3.5",
updated ecosystem packages
"feathers-hooks-validate-joi": "https://github.com/asamolion/feathers-hooks-validate-joi",
"feathers-knex": "^7.1.0",
"feathers-objection": "^4.3.0",
- Data
- DB
- postgresql
- Query Builder / ORM
- knex/objection
- DB
- Backend
- node
- Transports
- socket.io (websockets)
- express (REST)
- API
- feathersjs
- Frontend
- React
- Redux
- Server/Client Validation
- @hapi/joi
- Upgrade
@feathersjs/cli
- straightforward and useful for the migration - Run
feathers upgrade
This is largely due to some syntax changes.
before
authentication: {
secret: process.env.AUTH_SECRET,
strategies: process.env.AUTH_STRATEGIES.split(','),
header: process.env.AUTH_HEADER,
path: process.env.AUTH_PATH,
service: process.env.AUTH_SERVICE,
jwt: {
header: {
typ: process.env.AUTH_JWT_HEADER
},
audience: process.env.AUTH_JWT_AUDIENCE,
subject: process.env.AUTH_JWT_SUBJECT,
issuer: process.env.AUTH_JWT_ISSUER,
algorithm: process.env.AUTH_JWT_ALGORITHM,
expiresIn: process.env.AUTH_JWT_EXPIRESIN,
},
local: {
entity: process.env.AUTH_LOCAL_ENTITY,
service: process.env.AUTH_LOCAL_SERVICE,
usernameField: process.env.AUTH_LOCAL_USERNAMEFIELD,
passwordField: process.env.AUTH_LOCAL_PASSWORDFIELD,
}
}
after
- entity and service have moved into the parent
authentication
objection strategies
renamed toauthStrategies
jwt
renamed tojwtOptions
subject
removed from jwtOptions
NOTE all of these changes are listed in the official documentation
authentication: {
secret: process.env.AUTH_SECRET,
authStrategies: process.env.AUTH_STRATEGIES.split(','),
header: process.env.AUTH_HEADER,
path: process.env.AUTH_PATH,
service: process.env.AUTH_SERVICE,
entity: process.env.AUTH_LOCAL_ENTITY,
jwtOptions: {
header: {
typ: process.env.AUTH_JWT_HEADER
},
audience: process.env.AUTH_JWT_AUDIENCE,
issuer: process.env.AUTH_JWT_ISSUER,
algorithm: process.env.AUTH_JWT_ALGORITHM,
expiresIn: process.env.AUTH_JWT_EXPIRESIN,
},
local: {
usernameField: process.env.AUTH_LOCAL_USERNAMEFIELD,
passwordField: process.env.AUTH_LOCAL_PASSWORDFIELD,
}
}
The authentication service largely remained unchanged after using the upgrade tool.
However, there were necessary modifications to make the service compatible with
feathers-reduxify-authentication
The changes were made to after:create
due to feathers-reduxify-authentication
needing the
user object in a specific location to manage it within the redux store.
app.service('authentication').hooks({
after: {
create: [
context => {
context.result.data = context.result.user;
delete context.data.password;
return context;
}
]
}
});
Validation was the most affected by the change, and at this time the official
feathers-hooks-validate-joi
is not compatible with v4 of feathersjs. This is due
to the deprecation of the next()
function, as well as some rearranging of context.
A compatible fork is available at:
https://github.com/asamolion/feathers-hooks-validate-joi
After installing this forked version, I also upgraded @hapi/joi
. This created
some unexpected issues. The following modifications were performed:
- Modification of all schemas
Schemas now require and additional Joi.Object()
or `Joi.Object().keys({})
before
const schema = {
username: Joi.string()
.trim()
.alphanum()
.min(5),
password: Joi.string()
.trim()
.alphanum()
.min(8)
};
after
const schema = Joi.object({
username: Joi.string()
.trim()
.alphanum()
.min(5),
password: Joi.string()
.trim()
.alphanum()
.min(8)
});
While I was using Joi.Object.keys({schema})
for server-side validation. Client
validation was not. Probably just a mistake on my own part. Also, in a helper I use
for redux-form
, there was a required change to include an undefined
check in logic.
Form validation is handled like so
createValidator.js
export default function createValidator(schema) {
return values => {
const result = schema.validate(values, {
abortEarly: false,
stripUnknown: { objects: true }
});
if (result.error === null || result.error === undefined) {
return result;
}
const errors = result.error.details.reduce((all, cur) => {
const allErrors = Object.assign({}, all);
const path = cur.path[cur.path.length - 1];
const message = cur.message;
if (Object.prototype.hasOwnProperty.call(allErrors, path)) {
allErrors[path].push(message);
} else {
allErrors[path] = [message];
}
return allErrors;
}, {});
return errors;
};
}
loginContainer.js
(relevant portions shown)
import createValidator from '../../../common/helpers/createValidator';
import Joi from '@hapi/joi'
const schema = Joi.object({
username: Joi.string()
.trim()
.alphanum()
.min(5),
password: Joi.string()
.trim()
.alphanum()
.min(8)
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(
// decorate react component with redux-form
reduxForm({
form: 'UserSignIn',
validate: createValidator(schema),
onSubmitFail: onSubmitFail,
onSubmitSuccess: onSubmitSuccess,
onSubmit: handleSubmit
})(LoginForm)
);
In doing this, redux-form
is able to use @hapi/joi
for validation of the form
in real-time.
I ran into a couple errors wit using @hapi/joi
on the backend of my application as well.
This was due to a weird side-effect that, when using convert: true
within
feathers-hooks-validate-joi
, context.data
was getting a nested value
property.
The solution is fairly simple:
server/services/events/event.hooks/js
(relevant portion shown)
module.exports = {
before: {
create: [
...eventsValidation,
context => {
context.data = context.data.value;
return context;
}
]
}
}
A simple change, but it worked for the cases where I was using convert
.
So that's basically it. I may have missed some notes, and if so reach out! Hope this helps with people's v4 migrations.
-Brenden