티스토리 뷰
스키마 메소드 모듈분기
안녕하세요:)
지난 포스팅까지 우리는 몽구스 모듈을 활용해서 로그인과 관련된 여러가지 기능들을 구현해 보았습니다. 그런데 쭉쭉 잘 코딩하고 나니 기능적인 문제는 없지만 가독성이 떨어지는것이 문제였습니다. 세,네가지의 DB 운용 메소드들과 요청path에 따른 라우팅 미들웨어들을 쭉 열거하니 코드의 분량이 400라인이 훨신 넘어갔습니다ㅠㅠ
이번 포스팅에서 다루어볼 내용은 메인모듈에서는 스키마 관련 코드(메소드 및 필드 초기화)를 메인 코드에서 분기하여 모듈화하는것을 해보겠습니다.
만약 모듈을 분기한다면 메인이 되는 node파일에서의 가독성은 증가하게 되고 이는 디버깅시에도 훨씬 유리하게 작용할것입니다.
파이썬 장고 프레임워크에서는 새로운 웹프로젝트 또는 웹앱 에디팅을 시작하게 되면 분기되어있는 디렉터리를 가장먼저 제공해주지만 노드의 경우 디렉터리를 직접 만들어 사용해야합니다.
그럼 이제부터 어디서 부터 어떻게 분기해내고 어떻게 가져오는지 다루어 보겠습니다.
1. 유저 스키마 관련 메소드 모듈분기
이전에 우리는 아래와 같이 스키마를 선언했습니다. 스키마관련 메소드인 createUserSchema() 모듈 부분만 긁어 온것인데 100라인이 넘는 분량을 차지합니다. 저는 따로 user_schema.js 라는 파일을 만들어서 이 내용을 모듈화 해주고 원래의 코드에서 참조해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
function createUserSchema() {
// 스키마 정의
// password를 hashed_password로 변경, 각 칼럼에 default 속성 모두 추가, salt 속성 추가
UserSchema = mongoose.Schema({
id: {type: String, required: true, unique: true, 'default':''},
hashed_password: {type: String, required: true, 'default':''},
salt: {type:String, required:true},
name: {type: String, index: 'hashed', 'default':''}
});
// password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 가상 속성임.
// 특정 속성을 지정하고 set, get 메소드를 정의함
UserSchema
.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
console.log('virtual password의 set 호출됨 : ' + this.hashed_password);
})
.get(function() {
console.log('virtual password의 get 호출됨.');
return this._password;
});
// 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가
// 비밀번호 암호화 메소드
UserSchema.method('encryptPassword', function(plainText, inSalt) {
if (inSalt) {
return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex');
} else {
return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex');
}
});
// salt 값 만들기 메소드
UserSchema.method('makeSalt', function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
});
// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)
UserSchema.method('authenticate', function(plainText, inSalt, hashed_password) {
if (inSalt) {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText, inSalt), hashed_password);
return this.encryptPassword(plainText, inSalt) === hashed_password;
} else {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText), this.hashed_password);
return this.encryptPassword(plainText) === this.hashed_password;
}
});
// 값이 유효한지 확인하는 함수 정의
var validatePresenceOf = function(value) {
return value && value.length;
};
// 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)
UserSchema.pre('save', function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.password)) {
next(new Error('유효하지 않은 password 필드입니다.'));
} else {
next();
}
})
// 필수 속성에 대한 유효성 확인 (길이값 체크)
UserSchema.path('id').validate(function (id) {
return id.length;
}, 'id 칼럼의 값이 없습니다.');
UserSchema.path('name').validate(function (name) {
return name.length;
}, 'name 칼럼의 값이 없습니다.');
UserSchema.path('hashed_password').validate(function (hashed_password) {
return hashed_password.length;
}, 'hashed_password 칼럼의 값이 없습니다.');
// 스키마에 static으로 findById 메소드 추가
UserSchema.static('findById', function(id, callback) {
return this.find({id:id}, callback);
});
// 스키마에 static으로 findAll 메소드 추가
UserSchema.static('findAll', function(callback) {
return this.find({}, callback);
});
console.log('UserSchema 정의함.');
// User 모델 정의
UserModel = mongoose.model("users2", UserSchema);
console.log('users2 정의함.');
}
|
cs |
위에서 하나의 모듈안에 스키마와 관련된 내용들을 모두 코딩해보았습니다. 기능적인 내용은변하는것이 없이 객체를 선언하고 객체내의 임의의 메소드를 만들어 실행하는 방법으로 모듈화를 진행해보겠습니다. 먼저 모듈과 모듈내 메소드 선언에 대한 간단한 예제를 만들어 보았습니다.
1
2
3
4
5
6
7
8
9
|
var test = {}; //임의의 객체 선언
test.print = function() {
console.log("this is function test");
}
var exec = test; // 객체 내에 선언된 함수 활용
exec.print();
|
cs |
위와 같이 임의의 변수명인 test를 객체로 선언해주면 그안에 메소드를 선언해 줄수 있습니다. 저의 경우 print라는 함수를 만들어주고 결과를 확인하니 아래와 같았습니다.
위의 간단한 코드와 같은 원리를 이용한 user_schema.js 코드는 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
var crypto = require('crypto');
var Schema = {}; //임의의 객체 선언
//객체내의 메소드 선언
Schema.createSchema = function(mongoose) {
// 스키마 정의
// password를 hashed_password로 변경, 각 칼럼에 default 속성 모두 추가, salt 속성 추가
UserSchema = mongoose.Schema({
id: {type: String, required: true, unique: true, 'default':''},
hashed_password: {type: String, required: true, 'default':''},
salt: {type:String, required:true},
name: {type: String, index: 'hashed', 'default':''}
});
// password를 virtual 메소드로 정의 : MongoDB에 저장되지 않는 가상 속성임.
// 특정 속성을 지정하고 set, get 메소드를 정의함
UserSchema
.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
console.log('virtual password의 set 호출됨 : ' + this.hashed_password);
})
.get(function() {
console.log('virtual password의 get 호출됨.');
return this._password;
});
// 스키마에 모델 인스턴스에서 사용할 수 있는 메소드 추가
// 비밀번호 암호화 메소드
UserSchema.method('encryptPassword', function(plainText, inSalt) {
if (inSalt) {
return crypto.createHmac('sha1', inSalt).update(plainText).digest('hex');
} else {
return crypto.createHmac('sha1', this.salt).update(plainText).digest('hex');
}
});
// salt 값 만들기 메소드
UserSchema.method('makeSalt', function() {
return Math.round((new Date().valueOf() * Math.random())) + '';
});
// 인증 메소드 - 입력된 비밀번호와 비교 (true/false 리턴)
UserSchema.method('authenticate', function(plainText, inSalt, hashed_password) {
if (inSalt) {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText, inSalt), hashed_password);
return this.encryptPassword(plainText, inSalt) === hashed_password;
} else {
console.log('authenticate 호출됨 : %s -> %s : %s', plainText, this.encryptPassword(plainText), this.hashed_password);
return this.encryptPassword(plainText) === this.hashed_password;
}
});
// 값이 유효한지 확인하는 함수 정의
var validatePresenceOf = function(value) {
return value && value.length;
};
// 저장 시의 트리거 함수 정의 (password 필드가 유효하지 않으면 에러 발생)
UserSchema.pre('save', function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.password)) {
next(new Error('유효하지 않은 password 필드입니다.'));
} else {
next();
}
})
// 필수 속성에 대한 유효성 확인 (길이값 체크)
UserSchema.path('id').validate(function (id) {
return id.length;
}, 'id 칼럼의 값이 없습니다.');
UserSchema.path('name').validate(function (name) {
return name.length;
}, 'name 칼럼의 값이 없습니다.');
UserSchema.path('hashed_password').validate(function (hashed_password) {
return hashed_password.length;
}, 'hashed_password 칼럼의 값이 없습니다.');
// 스키마에 static으로 findById 메소드 추가
UserSchema.static('findById', function(id, callback) {
return this.find({id:id}, callback);
});
// 스키마에 static으로 findAll 메소드 추가
UserSchema.static('findAll', function(callback) {
return this.find({}, callback);
});
console.log('UserSchema 정의함.');
return UserSchema;
};
// module.exports에 UserSchema 객체 직접 할당
module.exports = Schema;
|
cs |
|
|
위의 코드에서 마지막 부분도 조금 유의 해야 합니다 이전포스팅에서는
UserModel = mongoose.model("users2", UserSchema);
이런식으로 모델링해주었지만 이번에는 UserSchema 객체를 return 해주었고 처음에 선언한 임의의 객체변수 Schema를 module.exports해주었습니다.
2. 메인 코드에서 스키마모듈 불러오기
메인코드에서는 스키마 모듈의 절대경로를 통해 모듈을 불러와주고 아래와 같이 각각의 변수와 메소드를 매핑시켜주면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 사용자 스키마 및 모델 객체 생성
function createUserSchema() {
// 2. user_schema.js 모듈 불러오기
UserSchema = require('./schemas/user_schema').createSchema(mongoose);
// UserModel 모델 객체 생성
UserModel = mongoose.model("users3", UserSchema);
console.log('users3 정의함.');
// 3. UserSchema와 UserModel 객체를 app에 추가
app.set('UserSchema', UserSchema);
app.set('UserModel', UserModel);
// init 호출
user.init(database, UserSchema, UserModel);
}
|
cs |
카테고리를 마친 소감.
mongoDB 카테고리는 이번포스팅을 마지막으로 종료입니다. (나중에 더 공부를 할수도 있습니다만 일단은 종료!)
웹페이지 속 비정형 데이터베이스 운용을 목표로 시작했었습니다. 처음에는 이리 오래 걸릴줄 모르고 쉽게봤었는데... 진행하다보니 점점 내용이 깊어짐에 따라 자료도 불충분하고 어려운점이 많았네요. 원래 목표로한 기간보다 두배는 더 걸린거 같습니다... 역시 개발자의 가장큰 역량중 하나는 구글링이라는 것을 한번더 깨닫게 되는 포스팅들 이었습니다.
앞으로의 계획.
이제 본래에 하던 프로젝트인 Node.js 웹개발로 돌아가 몽고디비와 모듈분기에 대한 내용들을 접목해볼생각입니다. 하계방학기간이 끝나기 전에 CRUD 기능을 갖춘 웹 앱 또는 사이트를 만들어보고 싶었는데 남은기간동안 분발해야할것같습니다. 기간이 이제 어림잡아 4주정도 있는것 같네요... 그중 한주는 영어시험공부를 해야할것같고 2주 안에 매일 코딩하면 가능할지도...? ㅎ 하루만 살아가는 esfp는 매일이 버겁네요... 여러분은 주어진 일에 기간이 많이 있다고 안심하지마세요...
그래도 차곡차곡 작업물들이 생기는것들을 보니 마냥 삽질만하고 있는것 같지는 않아 기분이 좋아지곤 하네요 ^_^
'Database > Express & MongoDB' 카테고리의 다른 글
Express & MongoDB - 데이터 암호화 (0) | 2021.08.04 |
---|---|
Express & MongoDB - 몽구스 모듈 (0) | 2021.08.04 |
Express & MongoDB - 수도 퀴즈 웹사이트 (0) | 2021.08.02 |
Express & MongoDB - DB 데이터 삽입, 수정 (0) | 2021.07.21 |
Express & MongoDB - DB 연동 (1) | 2021.07.20 |