当前位置:网站首页>Transfer the idea of "Zhongtai" to the code
Transfer the idea of "Zhongtai" to the code
2022-07-05 15:22:00 【Ardor-Zhang】
List of articles
hold ” Zhongtai “ The idea of moving to the code
Abstract : Different service providers correspond to different interfaces , How to avoid mixing judgment logic directly in the code ? How can I use it without caring about the interface provided by a service , What parameters are needed , What structure to respond to and what exception error to return ? This article is a good medicine , hold ” Zhongtai “ The idea of is introduced into the code , Solve this problem pointedly .
1 How to ~
First, let's take a look at a practical example , What problems have you encountered in the project .
When developing login registration function , There are two third-party services that users can choose at will —— Firebase and Supabase The way ( It can be understood as wechat and QQ land ), They provide the following capabilities :
- Email registration
- Firebase —— createUserWithEmailAndPassword
- Supabase —— signUp
- Mailbox validation
- Firebase —— sendEmailVerification
- Supabase —— emailForVerification
- Email login
- Firebase —— signInWithEmailAndPassword
- Supabase —— signIn
- Password reset
- Firebase —— sendPasswordResetEmail
- Supabase —— resetPasswordForEmail
- The user to log out
- Firebase —— signOut
- Supabase —— signOut
You can see , Different services have completely different interfaces , besides , The interfaces provided by different services also have the following differences :
- The required parameter formats are different
- The format of the returned response body is different
- The capture formats of exception errors are different
When used in a project , Because there is no logical unity , In the code A lot of judgment logic , It is used to realize that the bottom layer correctly uses the corresponding interface when users choose to use different services , Such as the following code :
// User registration logic
if( Services selected by users == Firebase) {
formatFirebaseParams() // Format registration parameters , Different services require different parameter formats
try {
response = createUserWithEmailAndPassword(...) // Firebase Registration logic
user = formatFirebaseResponse(response) // Format the return body , Different services have different return body formats
} catch (e) {
// Handling exceptions , Different services catch different exception error formats
if(e.code === ' The mailbox already exists ') {
throw ' The mailbox already exists '
} else if(){
} ....
...
}
} else {
formatSupabaseParams() // Format registration parameters
try {
response = registerByEmail(...) // Supabase Registration logic
user = formatSupabaseResponse(response) // Format the return body
} catch (e) {
// Handling exceptions
if(e.code === 1001) {
throw ' The mailbox already exists '
} else if(){
} ....
...
}
}
As you can see from above , Without unified treatment , these Logic is mixed directly, which is very chaotic in business , also , Predictably enough , With the increase of third-party services providing login , The logic here will be increased accordingly , This will bring huge costs to the development :
- Just add a new service type , Every place using services needs to add corresponding logic
- Just add a new place to use , You need to add the logic corresponding to all services
2. reflection ?
Is there a way to solve this problem ? It can realize the following features :
Interface for unified use
- Whether the user chooses Firebase still Supabase, The unified interface is called in the business code , Such as createUser(email, password), No longer differentiate Services .
- meanwhile , There is no need to format parameters by services when calling business code
Unified return body format
- Whether the user chooses Firebase still Supabase, The structure of the response body returned when used in the business code is consistent
Unified exception capture format
- Whether the user chooses Firebase still Supabase, For the same type of error , The errors returned during capture are consistent
3. Walk up !
How can we make different services provide the same set of interfaces ? It's not hard to think , Namely Zhongtai Thought , Realize a middle platform :
- foreign : Provide unified interface services to business parties , Of course, business parties can choose the underlying services they want to use at will
- internal : Put different underlying services together , Encapsulate their interfaces into consistent interfaces , Include :
- Format of parameters
- Interface encapsulation
- Unified capture of abnormal errors
Unified interface
Use abstract classes to unify exposed interfaces
export default abstract class AuthBase { abstract initialize(): void; abstract get currentUser(): User; abstract createUser(email: string, password: string): Promise<User>; abstract emailVerification(): Promise<void>; abstract loginIn(email: string, password: string): Promise<User>; abstract logOut(): Promise<void>; abstract passwordReset(email: string): Promise<void>; }
Encapsulate third-party services based on abstract classes
import { createUserWithEmailAndPassword } from "firebase/auth"; import { WeakPasswordAuthException, EmailAlreadyInUseAuthException, InvalidEmailAuthException, GenericAuthException, } from "../auth_exceptions"; // firebase To implement the base class export default class FirebaseAuthProvider implements AuthBase { auth: Auth; initialize(): void { ... } get currentUser(): User { ... } // Implement unified methods in base classes async createUser(email: string, password: string): Promise<User> { // If you need to format parameters , Do it here try { // call firebase Corresponding services const { user } = await createUserWithEmailAndPassword( this.auth, // firebae Required parameters email, password ); // Return the unified response body structure return { id: user.uid, email: user.email!, isEmailVerified: user.emailVerified, }; } catch (e) { switch (e.code) { // Capture the error , And throw a unified error response case "email-already-in-use": throw new EmailAlreadyInUseAuthException(); case "weak-password": throw new WeakPasswordAuthException(); case "invalid-email": throw new InvalidEmailAuthException(); default: throw new GenericAuthException(); } } } async emailVerification(): Promise<void> { ... } async loginIn(email: string, password: string): Promise<User> { ... } async logOut(): Promise<void> { ... } async passwordReset(email: string): Promise<void> { ... } }
import { User } from "../types"; import AuthBase from "../auth_base"; import { createClient, SupabaseClient, AuthUser } from "@supabase/supabase-js"; import { WeakPasswordAuthException, EmailAlreadyInUseAuthException, InvalidEmailAuthException, GenericAuthException, } from "../auth_exceptions"; // supabase To implement the base class export default class SupabaseAuthProvider implements AuthBase { supabase: SupabaseClient; initialize(): void { ... } get currentUser(): User { ... } // Implement unified methods in base classes async createUser(email: string, password: string): Promise<User> { try { const { user, error } = await this.supabase.auth.signIn({ email, // supa Required parameters password, }); if (user !== null) { // Return the unified response body structure return { id: user?.id, email: user.email!, isEmailVerified: !!user.new_email, }; } else { const status = error?.status; switch (status) { // Capture the error , And throw a unified error response case 1001: throw new EmailAlreadyInUseAuthException(); case 1002: throw new WeakPasswordAuthException(); case 1003: throw new InvalidEmailAuthException(); default: throw new GenericAuthException(); } } } catch (e) { throw new GenericAuthException(); } } async emailVerification(): Promise<void> { ... } async loginIn(email: string, password: string): Promise<User> { ... } async logOut(): Promise<void> { ... } async passwordReset(email: string): Promise<void> { ... } }
ad locum , Base class based , We have achieved
Encapsulate the corresponding interfaces of each service and provide a unified external interface
Unified return body format
Unified error capture
Aggregation of multiple services
import { User } from "./types"; import AuthBase from "./auth_base"; import FirebaseAuthProvider from "./provider/firebase_auth_provider"; import SupabaseAuthProvider from "./provider/supabase_auth_provider"; const providerMap = { firebase: new FirebaseAuthProvider(), supabase: new SupabaseAuthProvider(), } as const; export type ProviderEnum = keyof typeof providerMap; // Aggregate all services , Businesses do not need to be aware of the underlying services when using , Use a unified interface directly export default class AuthService implements AuthBase { constructor(private provider: AuthBase) { } static instance(provider: ProviderEnum) { return new AuthService(providerMap[provider]); } initialize(): void { this.provider.initialize(); } get currentUser(): User { return this.provider.currentUser; } createUser(email: string, password: string): Promise<User> { return this.provider.createUser(email, password); } emailVerification(): Promise<void> { return this.provider.emailVerification(); } loginIn(email: string, password: string): Promise<User> { return this.provider.loginIn(email, password); } logOut(): Promise<void> { return this.provider.logOut(); } passwordReset(email: string): Promise<void> { return this.provider.passwordReset(email); } }
Use
import AuthService from "./auth/auth_service"; import { WeakPasswordAuthException, EmailAlreadyInUseAuthException, InvalidEmailAuthException, } from "./auth/auth_exceptions"; // When a user chooses to use a third-party service , Just instantiate it here , All subsequent interfaces are consistent , There is no need to make any judgment const provider = AuthService.instance("firebase"); // No matter what service you use , When used, there are consistent interfaces 、 Parameters 、 Response body and error response async function handleRegister(email: string, password: string) { try { const user = await provider.createUser(email, password); // user use the same pattern } catch (e) { if (e instanceof EmailAlreadyInUseAuthException) { // Throw the corresponding error message } else if (e instanceof WeakPasswordAuthException) { // Throw the corresponding error message } else if (e instanceof InvalidEmailAuthException) { // Throw the corresponding error message } else { // Throw the corresponding error message } } }
When users choose a service , There is no need to care about the user's choice in the business code , There is no need to make any logical judgment , Just select the corresponding service when initializing the instance , All subsequent logics do not need to judge and handle different services in the business , Because it 's already :
- Unified interface
- Unified return body
- Unified exception error
4. Think …
In fact, such an idea is not difficult , But it's hard to see in the project , Students who are not developers cannot write , More should be not thinking in this direction , I didn't follow up conceptually .
Record such thoughts here , After that, as long as you encounter the same scene , Try to lean in this direction . I Believe , Such code is readable and maintainable , Will be much higher .
边栏推荐
- 如何将 DevSecOps 引入企业?
- Install and configure Jenkins
- Ctfshow web entry explosion
- Mongdb learning notes
- Super wow fast row, you are worth learning!
- CPU design practice - Chapter 4 practice task 3 use pre delivery technology to solve conflicts caused by related issues
- Want to ask the big guy, is there any synchronization from Tencent cloud Mysql to other places? Binlog saved by Tencent cloud MySQL on cos
- Easyocr character recognition
- 我这边同时采集多个oracle表,采集一会以后,会报oracle的oga内存超出,大家有没有遇到的?
- Does maxcompute have SQL that can query the current storage capacity (KB) of the table?
猜你喜欢
[JVM] operation instruction
Bubble sort, insert sort
Au - delà du PARM! La maîtrise de l'Université de Pékin propose diverse pour actualiser complètement le classement du raisonnement du NLP
Interview shock 62: what are the precautions for group by?
Selection and use of bceloss, crossentropyloss, sigmoid, etc. in pytorch classification
12 MySQL interview questions that you must chew through to enter Alibaba
I spring and autumn blasting-1
Database learning - Database Security
swiper. JS to achieve barrage effect
Misc Basic test method and knowledge points of CTF
随机推荐
Hongmeng system -- Analysis from the perspective of business
P6183 [USACO10MAR] The Rock Game S
Huawei Hubble incarnation hard technology IPO harvester
Cartoon: programmers don't repair computers!
百亿按摩仪蓝海,难出巨头
What are the domestic formal futures company platforms in 2022? How about founder metaphase? Is it safe and reliable?
你童年的快乐,都是被它承包了
Talking about how dataset and dataloader call when loading data__ getitem__ () function
Common interview questions about swoole
lvgl 显示图片示例
Bugku's steganography
Where is the operation of convertible bond renewal? Is it safer and more reliable to open an account
CPU design practice - Chapter 4 practical task 2 using blocking technology to solve conflicts caused by related problems
NBA赛事直播超清画质背后:阿里云视频云「窄带高清2.0」技术深度解读
JS topic - console log()
Misc Basic test method and knowledge points of CTF
Super wow fast row, you are worth learning!
1330:【例8.3】最少步数
CODING DevSecOps 助力金融企业跑出数字加速度
Want to ask the big guy, is there any synchronization from Tencent cloud Mysql to other places? Binlog saved by Tencent cloud MySQL on cos