$ npm install -g @feathersjs/cli
$ mkdir feathers-chat
$ cd feathers-chat
$ feathers generate app
chọn tên cho project - enter để lấy tên thư mục tên folder để chưa file source, mặc định là src chọn package manager (npm or yarn) chọn dạng kết nối → chat → REST với REaltime via socket TEsting framework ? Mocha + assert hay Jest App có authentication không dạng code convension (ESlint) cách authentication (Oauth, local, ...) mongodb+srv://admin:admin@cluster0-0ssna.mongodb.net/feathers?retryWrites=true&w=majority
$ npm start
Cấu trúc thư mục
config/
default.json chứa các tùy chỉnh cơ bản của webservice
production.json chưa các tùy chỉnh khi ứng dụng ở chế độ production NODE_ENV = production
public/ chứa các static file, index.html để hiển thị khi vào trang chính của server
src/
hooks/ chưa các hooks của feather
services/ chưa các service do feather generate ra
users/ là service được tạo ra để đăng kí và phân quyền user
users.class.js là service class
users.hook.js là các hook của service này
users.service.js dùng để đăng kí service này trên trang ứng dụng của feathers
middleware/
models/ chưa các file định nghĩa model trong db
users.model.js setup user collection
app.js
app.hooks.js đăng kí các hook dùng cho các service
authentication.js , setup phần phân quyên cho ứng dung
channels.js setup event channels dành cho socket ..
index.js load và start app
test/
services/ services test
users.test.js các test cơ bản của user service
app.test.js test các trường hợp cơ bản như index page hay 404
authentication.test.js test cho phần phân quyền
Services
Service là một object hoặc class thực hiện implements một method nào đó. tạo một interface để kết nối với các dữ liệu như
gọi các services khác như Các service method là các hàm CRUD mà một service có thể có. bao gồm
find → find toàn bộ data hoặc một phần thõa query update → update bằng cách thay thế hoàn toàn cái mới patch → update 1 phần bằng cách merger với cái đã có class MyService {
async find(params) {}
async get(id, params) {}
async create(data, params) {}
async update(id, data, params) {}
async patch(id, data, params) {}
async remove(id, params) {}
}
app.use('/my-service', new MyService());
id → unique identifier of data data → data được send bởi user dùng cho create, update, patch params (optional) → các params thêm như là để auth or query service.find({ query: {} })
Đăng kí service với app
app.use(’messages’, new MessageService());
Để nhận service object và sử dụng các service method
const messageService = app.service('messages');
const messages = await messageService.find();
Service Events
Service sau khi được đăng kí với app sẽ thành một NodeJS EventEmitter sẽ gửi event và data . Event sẽ được lắng nghe bằng cách
app.service(’messages’).on(’eventName’, data => {});
Tạo thêm serviec
feathers generate service
kind of service → mongoose luôn
name of sservice→ messages
path: → /messages
required auth ? → yes
Config lại service User thêm avatar
chỉnh lại các service ta vào ....class.js
ta chỉnh service user.class.js
...
Hook
Ta thấy ta có thể thêm các hàm process vào service để tủy chỉnh ứng dụng
Nhưng có nhiều trường hợp, ta cần một hàm chạy trong nhiều service
Ví dụ authen tất cả các service xem user có quyền sử dụng hay không
Hoặc thêm trường thơief gian vào tất cả dữ liệu ta thêm
Nếu tùy chỉnh bằng các hàm trong services ta sẽ phải làm đi làm làm công đoạn thêm hàm với mỗi service
→ HOOK
hook là một middlerware function được đăng kí vào các giai đoạn before, after, error của các service methods/
ta có thể gán nhiều hook cho một method để tạo nên một flow phức tạp Hook thường được dùng cho các việc như là validation, auth, logs, sinh các entities, send notification và nhiều cái nữa
Hook function - hàm hook
là func dùng hook context là param và trả về context đó( đã được chỉnh sửa) hoặc không trả về gì.
Hook được chạy theo thứ tự nó được đăng kí. Nếu một hook quăng lỗi → tất cả các hook khác và service có hook đó sẽ skip và sẽ tới phiền errors.
Pattern cho việc tạo hook dễ tái sử dụng là dùng một wrapper function nhận các option và trả về một hook
const hookName => options => async context => { ... return context }
hook context là object chưa thông tin về hàm service gọi hook
2 loại context là read only và wriable
context.app - The Feathers application object. This can be used to e.g. call other services context.service - The service this hook is currently running on context.path - The path (name) of the service context.method - The service method name context.type - The hook type (before, after or error) context.params - The service method call params. For external calls, params usually contains: context.params.query - The query (e.g. query string for REST) for the service call context.params.provider - The name of the transport (which we will look at in the next chapter) the call has been made through. Usually rest, socketio, primus. Will be undefined for internal calls. context.id - The id for a get, remove, update and patch service method call context.data - The data sent by the user in a create, update and patch service method call context.error - The error that was thrown (in error hooks) context.result - The result of the service method call (in after hooks) register hook
để đăng kí hook ta đăng kí trong file .hooks.js của các service
Khi nào dùng hook, khi nào extended service khi nào custom service
chức năng được dùng nhiều hơn một nơi (validation, permission) Đó không phải chức năng chính của service và service có thể hoạt động không có nó (gửi email sau khi create user) chức năng chỉ dùng trong service này service không thể hoạt động thiếu nó nhiều service combined với nhau (report) Service làm nhiều thao tác khác chứ không chỉ nói chuyện với db (call another API, sensor) Authentication
POST /users → create user {
“email”:”aquarius.superstar@gmail.com”,
“password”:”quang123”
}
→ vào db thấy tạo ra được user
Authen POST /authentication → READ
{
"strategy":"local",
"email":"aquarius.superstar@gmail.com",
"password":"quang123"
}
→ có được token → gửi vào postman: Authorization: Bearer <Token>
Gắn auth with github
http://localhost:3030/oauth/github/callback
ta sẽ lấy được ClientId và client secret bỏ vào file config/default.json phần authentication {
"authentication": {
"oauth": {
"redirect": "/",
"github": {
"key": "<Client ID>",
"secret": "<Client Secret>"
}
},
// Other authentication configuration is here
// ...
}
}
Update src/authentication.sj const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
const { LocalStrategy } = require('@feathersjs/authentication-local');
const { expressOauth, OAuthStrategy } = require('@feathersjs/authentication-oauth');
class GitHubStrategy extends OAuthStrategy {
async getEntityData(profile) {
const baseData = await super.getEntityData(profile);
return {
...baseData,
// You can also set the display name to profile.name
name: profile.login,
// The GitHub profile image
avatar: profile.avatar_url,
// The user email address (if available)
email: profile.email
};
}
}
module.exports = app => {
const authentication = new AuthenticationService(app);
authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());
authentication.register('github', new GitHubStrategy());
app.use('/authentication', authentication);
app.configure(expressOauth());
};
Để login với github ta chỉ cần visit localhost:3030/oauth/github
Tạo user → tạo 1 account kèm theo
Tạo 1 OTP → Tìm user_id có tồn tại chưa → có thì update new OTP, chưa thì create → gửi mail
Tạo 1 transaction → có OTP kèm theo, Kiểm tra → ktra ok tạo transaction.
Create User
Create OTP
OTP have User Information