내일 점심시간 전까지 과제를 제출해야 하기 때문에, 사실상 오늘이 마지막 날이다. 

 

 

 

도전 과제의 기능까지 구현은 모두 완료된 상태이다.

모아 놓고 보니까 API 의 수가 꽤 많은것을 확인 할 수 있다.

 

뭐 하나 쉬운게 없었다 !!

 

 

최종적으로 과제 제출을 위해선, 

 

 

마무리 단계인 AWS 배포까지 진행해 보도록 하자.

 

윈도우 환경이기 때문에 Git Bash 로 진행했고, 

EC2 구성은 이전에 강의를 듣고 중지시켜놨던 인스턴스를 다시 활성화 시켜서 사용하기로 했다.

 

git을 통해 파일을 받아올 것이기 때문에, gitignore 설정이 잘 되어있는지 확인하고  push 해놓자.

 

.env 파일이 같이 업로드 된다면 대여한 서버에서 무슨일이 생길지 모른다.

 

그렇다면 업로드 하지 않은 .env 는 어떻게 ubuntu 에게 보낼까?

 

 

검색 결과, vim 을 통해서 .env 를 생성하거나 수정 할 수 있다는 사실을 발견 !

 

 

불편하기 짝이없는 linux 환경을 잠시나마 경험할 수 있었다.

 

:wq 를 통해 해당 작업을 저장하고 종료할 수 있다.

 

이제 실행만 app.js를 실행하기만 하면 !

당연히 안된다. 구동에 필요한 패키지를 설치해야 하기 때문이다.

 

yarn  명령어를 통해, 패키지를 설치 하면 본격적으로 

EC2 의 IPv4 주소와 포트를 통해, 배포가 가능하다 !

 

insomnia 를 이용한 요청과 응답이 정상적으로 이루어지는 모습이다.

 

예상치 못한 난관이 있을것만 같았지만, 큰 어려움은 없었다.

방법을 깨달았으니

 

남은 시간동안은 다시 코드를 재정비하고, 업로드 후 재설치하고 배포할 시간이 될 듯 하다.

 

 

다음 내용으로, 

과제 내내 나를 괴롭혔던 부분에 대한 해답이 밝혀졌다 !

 

예상했던대로, header 를 통해서 토큰을 발행하면

클라이언트가 해당 토큰과 함께 요청을 전달해 주는것이 맞는 내용이었다.

 

로그인을 통해, jwt 를 발행하고 전달하는것은 cookie와 크게 다르지 않지만, 

 

 

해당 토큰은 insomnia 기준으로 authorization Headers 를 통해 클라이언트에 발행하고,

 

 

클라이언트는 서버의 인가가 필요한 사항에 대해서, Auth 에 TOKEN을 담아서 서버에 요청을 보내게 된다.

 

요청하며 보낸 토큰이 비정상적이라면, 당연히 정상적인 응답을 받을 수 없다.

 

 

계속 마음에 걸렸던 부분을 해결한 것 같아 한결 편안해졌다.

나머지  미흡한 부분도 많지만, 벽 처럼 느껴졌던 과제를 어느정도 해결 해 낸것 같아서 다행이다.

 

 

 

 

어제 고민했던 캐릭터 검증 코드를 미들웨어로 만들기로 했다. 

 

문제는, 실제로 미들웨어를 어떻게 작동되게 하는지 모르고있다는것...

미들웨어에 대한 개념 자체가 부족한 상태이다.

 

그 결과.....

 

해당 미들웨어를 갑자기 API 본문에 함수호출 형태로 작성을 하는 사태가 벌어졌다.

 

굉장히 민망한 상황이지만, 이게 잘못된 방법이라는 것은 바로 느껴졌기 때문에

미들웨어에 관한 학습을 다시 진행한 결과,

 

 

해당 형태로 순차적으로 미들웨어가 실행될 수 있게 하였다.

민망했던 위의 코드와 차이점을 살펴보면, 

 

처음 작성한 코드는 미들웨어(async 핸들러) 내부에서 호출되었기 때문에

return 을 반환 하더라도 다음 코드가 '당연히' 실행된다.

 

하지만,

아래에 작성한 코드는, 호출된 미들웨어가 next()를 받지 못하고  return 된다면

결국 => { } 의 내용으로 넘어가지 못하고 그대로 종료된다.

 

추가로 !

CharacterAuth(req, res);  형태는 그냥 함수의 호출이기 때문에 아예 잘못된, 완전 틀려먹은 접근이라고 생각했는데,

미들웨어 자체가 함수의 호출과 비교해서 크게 다를바가 없기 때문에, 호출한 위치가 잘못된 것이고 !

함수로서 호출하는 발상은 100% 틀려먹은 생각인것은 아니다 ! 라는 피드백을 받을 수 있었다.

 

 

 

다음으로 구현한 API는, 도전 기능에 해당하는 장비 장착 API 이다.

뭔가 많은 과정들이 SKIP 된거 같긴하지만...

 

해당 과제,  그것도 도전 기능의 BOSS 에 해당하는 API 라고 생각되는 부분이다.

 

 

API요구 사항은 위와 같다.

해당 내용을 토대로, 구현하기 전에 구상을 먼저 해보면,

 

우선, 해당 API를 실행하기 위해서는 !!!

 

로그인 인증을 거쳐야 하며, > login DB 조회

param으로 전달받은 characterId 도 검증해야하고 > character DB 조회

인벤토리의 아이템을 장착해야 하기 때문에 > inventory DB 조회

장착한 아이템의 능력치를 참조해야 하기 때문에 > item DB 조회

모든 테이블이 필연적으로 한 번씩, 조회될 수 밖에 없다.

 

그리고, 장비의 장착으로 인한

캐릭터의 능력치가 update, 아이템 상태의 update 또는 delete 등

데이터베이스의 수정이 여러번 발생하게 되기 때문에, 트랜잭션 구성을 생각해 둘 필요가 있다.

 

 

첫 코드부터 난관이었다. 

 

이유는, 장착 대상이 된 인벤토리의 아이템을 특정해야 하는데, 

characterId 와 itemId 로는 정확한 inventoryId 를 특정할 수 없다.

같은 캐릭터가 동일한 아이템 여러개를 인벤토리에 보유할 수 있기 때문이다.

11 캐릭터가 13 아이템 2개를 가지고 있다

제시한 두 가지의 정보로만 검색을 하면, 복수의 값이 결과로 나올 수 있다는 것이다.

어떤 아이템을 장착해야 할 지 

 

해결방안

1. 인벤토리의 PK에 해당하는 inventory_id 를 추가로 입력받아 진행한다.

-> 과제 요구사항에 벗어나며, 별로다 !!

 

2. 딱히 쓸데 없었던 inventory_number 라는 컬럼을 활용해 보자.

--> 예상되는 문제점이 있으나, 현 상황에선 큰 문제는 아니기 때문에 진행 !

 

 

 

사실, 위에 올린 이미지가 inventory_number 를 활용한 이미지 이다.

여기서, inventory_number는, 어떤 아이템이건 획득 당시에 

 

해당 캐릭터가 보유한 아이템들 중, 가장 높은 inventoryNumber +1 의 값을 부여한다. 

 

본래 의도는 가장 최소 값을 찾아 들어가게 할 예정이었으나, 

생각보다 로직이 복잡하고, 시간이 급박하기 때문에

 

일단은, 임시로 같은 캐릭터 id 내에서 중복되지는 않는 값을 갖도록 구현을 해 놓았다....

때문에 그다지 의미있는 컬럼이 아니게 되었지만,

결과적으로, 현재는 해당 값이 가장 작은 item을 지정하는 방향으로 구현이 된 상태다.

 

 

추가로,

이미 장착중인 아이템 중에,

위에서 특정한 아이템과 같은 타입인 것이 조회될 경우는 

에러를 리턴하도록 하고, 해당 사항이 없다면

 

 

 

아이템DB를 조회하고, 해당하는 능력치를 올려주는 update 문을 작성해서 마무리 했다.

 

일단 작동은 잘 되고 있기에, 여유가 될 때에 구상해뒀던 트랜잭션 부분이나, 

inventoryNumber 가 최소값을 찾아 들어가게 하는 방법을 적용할 예정이다.

 

 

 

 

네트워크 계층이란?

 

OSI 7계층 중, 3계층에 속하는 내용으로, 망 계층 이라고도 불립니다.

 

네트워크 계층의 대표적인 역할은,

라우팅(Routing) 과 포워딩(Fowarding) 입니다.

 

 

라우팅은

길 찾기에 해당하는 내용이며, 네트워크 계층 내에서 Control Plane 으로 나누기도 합니다.

출발지에서 목적지 까지의 경로 중, 가장 효율적인 경로를 탐색하는 것을 말합니다.

 

포워딩은

네트워크 계층 내에서 Data Plane 으로 나누기도 하며,

최선의 경로를 따라서 실제로 데이터를 전달하는 기능을 말합니다.

 

 

데이터 링크 계층과의 차이

데이터 링크 계층은 인접한 두 노드 간의 전송을 담당하는 것이고, 

네트워크 계층은 전체 네트워크 상에서 최종 수신지 까지의 전송을 담당합니다.

 

 

 

IP (인터넷 프로토콜, Internet Protocol)

목적지 까지 데이터를 전달하는 기능을 수행하고, 주소를 관리하는 기능을 수행합니다.

IP를 통해서 포워딩이 이루어진다 라고 볼 수 있습니다.

IP 주소 라고 불리는 인터넷 상의 고유 식별 번호를 통해 실제 데이터의 출발지와

목적지 등 각각의 주소(위치) 를 정의 할 수 있습니다.

 

 

 

DHCP (Dynamic Host Configuration Protocol)

클라이언트에게 동적으로 IP 주소를 할당하는 방법을 제공하는 프로토콜 입니다.

 

DHCP 의 특징

-주소의 대여시간 갱신 (연장)

-동일한 주소의 재 사용 가능

-네트워크에 접속하고자 하는 이동 사용자 지원

 

 

 

NAT ( Network Address Translation)

라우터 등의 장비에서 사설 IP를 외부IP 로 변환하는 기술입니다.

 

만약, 네트워크 내에 엄청나게 많은 호스트가 있다면, 호스트 마다 IP 주소를 할당하는데에는

너무 많은 IP 주소가 필요할 것 입니다. 하지만 실제로는 외부 인터넷이 내부 인터넷에 존재하는

모든 호스트에게 IP 주소를 직접 할당 해주는 것이 아닌, 라우터에게 IP 주소를 할당해줍니다.

결국 라우터 내부의 네트워크는 사실상 모두 같은 IP 주소를 사용하는것 보일 수 있습니다.

 

하지만, 내부 네트워크에서만 사용할 수 있는 또 다른 IP 주소를 부여받게 되고 이를 사설 IP 라고 부릅니다.

 

결과적으로, 내부 네트워크에 존재하는 사설 IP를 외부 IP 로 변환 및 매핑시켜주는것이 NAT 라고 할 수 있습니다.

 

 

월요일이되고, 가장 먼저 캐릭터 접속 authorization 을

추가로 만든것과 관련한 의견을 튜터님께 물었다.

 

 

주말 간 진행한 내용으로,

결론만 말하면, 결과는 폭망이다.

 

오늘은 그 과정에 대한 내용을 서술하도록 하겠다.

 

로그인만 인증하는 기존의 authorization (미들웨어) 에 더해서 

로그인 + 캐릭터 인증까지 검증하는 authorization 를 추가로 만든 것이고,

 

이렇게 만든 이유는,

1. 캐릭터 특정이 필요한 상황 (아이템 획득, 구매 등등) 에서 매번 캐릭터id를 param으로 받지 않아도 된다.

 -> 캐릭터 인증 (접속) 을 통해 해당 캐릭터 id를 고정할 수 있음

 

2.  param으로 캐릭터Id를 받을 경우 매번 해당 캐릭터Id 가 로그인한 계정에 포함이 되어 있는지 

검증을 해야하는데, 그 과정이 캐릭터 접속API에 포함되며, 

이후로는 JWT 복호화를 통해 검증함으로써 보안에도 유리함.

 

 

단점을 따지면,

 

1. 불필요한 코드일까 ? or 잘못된 접근 방식일까? 하는 막연한 생각 정도?

 

 

결론은

단호하게 '안된다' 였고,

해당 코드를 無로 돌릴것을 권장하셨다.

 

물론, 최대한 부드럽게 말씀해주시긴 했지만,

뭔 쓰잘데기 없는 코드를 만들어왔어? 라고 생각하셨음이 ' 제 6의 감각' 으로 느껴졌다...

 

코드 복잡성도 늘어나고, 불필요한 실행도 늘고, 유지보수에 대한 문제 등등을 지적하셨다.

 

 

납득이 되지 않았다.

 

 

과제에서 요구한 방식인 params 로 캐릭터id를 받아도

기존 JWT인증 + 로그인계정에 있는 캐릭터Id가 맞는지에 대한 검증은 해야하기 때문에,

캐릭터Id params를 받는 모든 API에   로그인계정에 있는 캐릭터Id인가- 에 대한 검증 코드가 필요하다.

 

당연히, 그런 API 는 다수 일 것이기 때문에, 동일한 내용을 복붙을 하거나, 

해당 캐릭터 인증만 하는 미들웨어를 어차피 만들어야 할 것이다.

 

 

실행할 것이 늘어난다? 

1의 내용은 어차피 실행되어야 할 내용 두가지를 합쳤을 뿐이고,

추가적으로 캐릭터 접속 API를 따로 진행해야 한다는 것인데,

그것이 즉시 폐기 라는 대답이 나올 정도로 불필요한 일인지 모르겠다.

 

오히려 캐릭터 접속API는 캐릭터 검증을 위한 데이터 베이스 조회를 한 번만 하고, 

이후로는 JWT 복호화를 통해 진행하므로, 코드 복잡도 면에서 오히려 유리하다.

==> 24.09.10 일 내용 정정

복호화로 얻은 정보를 바탕으로 find를 실행하기 때문에 데이터 베이스 조회 횟수는 같다.

============================================================================

 

심지어 JWT 복호화는 추가적인 작업이 아니라 기존에 계정Id를 복호화 하던것에 더해진 것이기 때문에,

이부분도 크게 차이가 없다.

물론, JWT 코드 자체가 복잡해질 수 있는 문제는 있다.

 

 

 

내가 놓친 부분이 있을까?  

별다른 수가 없다.

일단 피드백 받은 내용대로 갈아엎은 결과와 지금을 비교하는게 최선일듯 하다.

 

 

 

우선 만들어 놓은 아이템 획득 API를 기존의 요구 방식대로 바꿔보자.

 

위 처럼만 해놓으면, 아무계정이나 로그인해서 모든 캐릭터에 접근 할 수 있으니, 

캐릭터 검증 과정이 필요하다.

 

 

해당 코드를 추가하여, 검증을 하여야 한다.

이 과정에서 character.find 조회 과정은 반드시 필요함.

 

결국, 만들었던  캐릭터 접속 과정은, 

기존 로그인 JWT + 저 위에 코드를 합체한 내용일 뿐이다.

 

캐릭터 접속 할때 동일한 검증을 한다.

 

차이는 캐릭터 접속 API를 이용해야 한다는 점...

이 과정 자체가 문제일까?

 

 

JWT에  추가로 characterId 가 들어가기 때문에 JWT 토큰이 무거워진다는 단점도 있을 것이다. 

 

차라리,

늦게 확인한 것은 안타깝지만 해당부분은 과제 요구사항에서 벗어나기 때문에 안된다.

 

라는 대답이 돌아왔다면 머리가 아프진 않았을텐데...

 

심란하다

 

 

 

그렇게 바뀐 아이템 획득 API 이다. 

 

본인 캐릭터 확인 절차는 따로 미들웨로 만들기엔 좀 짧지 않나 생각도 들고...

그냥 복붙 해서 쓰자니, 유지보수가 어려워진다.

 

해결방안?

 

만약, 캐릭터 검증이 필요한 API 의 경우, _auth 가 더해진 param을 받아서

 

 

기존 로그인 미들웨어에 해당 구문을 추가하여, character_id_auth 를 param으로 받은 경우에만

검증을 진행하도록 했다.

 

물론 이 해결방안도 상당히 짜치는 구조이다.

 

굳이 login 검증만 하던 미들웨어에,  조건 한정으로 캐릭터검증을 하는 일을 부여했으니 말이다.

 

말하자면,

때에 따라 캐릭터 검증도 하는 유능한 login 검증 미들웨어가 아니라,

이걸 왜 나한테 시키지? 라는 상황의 login 검증 미들웨어가 된것에 가깝다.

 

login 검증 미들웨어가 실행 되면, 반드시 character_id_auth 의 존재를 체크해야 하고,

필요없다면 undifined를 정의한채로 넘어가는 불필요한 동작이 생긴 것이다.

 

해결방안의 해결방안?

 

1. 비록 긴 코드는 아니지만, 캐릭터 검증만을 위한 미들웨어를 만든다.

 

폐기된 코드가 떠오르는 방안이지만, 엄연히 차이가 있다.

폐기된 코드 => 기존 A 작업 + 새로운 B 작업 을 합쳐놓은 C작업을 만든것이고,

 

해당 방안은 => 새로운 B작업만 만들고, 필요에 따라 A 와 B를 각각 호출하는 것이다.

 

그런데B가 실행되는 상황에서는 반드시 A도 실행되어야 하는 상황인데..?

그래서 A+B 를 합친 C를 만들었던 것인데....??

 

여기서, 의문이 들었던 부분을 추가로 짚고 넘어가보자..

 

JWT 인증 + param으로 characterId를 받는 상황이라면,

해당 API는 전부 캐릭터 검증을 추가로 해야한다는건 이미 여러번 설명한 내용이다.

그렇게 되면 캐릭터 인증만하는 미들웨어를 추가하던지, API 마다 검증하는 코드를 붙여넣던지 간에,

character 데이터 베이스를 조회해야 한다. API가 실행될 때마다 find를 통해, character Id를 찾아 검증해야 하기 때문이다.

 

폐기된 방법 ( 캐릭터 접속 API를 만들고, 로그인검증+캐릭터검증에 해당하는 미들웨어를 추가) 의 경우,

기존에 있던 로그인 검증과 동일하게, 캐릭터 접속 당시에만 데이터 베이스를 조회하고

문제가 없을경우 JWT를 발급해서, 이후 발생한 검증은 발급한 JWT를 복호화를 통해 진행되기 때문에,

보안적인 면에서도 유리하고, DB조회도 접속시 1회만 하면 되기 때문에 복잡도 면에서도 유리하다.

==> 24.09.10일 정정

DB 조회는 미들웨어에서도 진행하기 때문에 미들웨어 호출당 1회의 조회를 하게 됨

 

또, 한번의 접속으로 캐릭터를 계속해서 특정할 수 있기 때문에,

클라이언트가 API 마다,  캐릭터id 를 param으로 전달해줘야 하는 일도 없어진다.

 

 

나는 틀리지 않았다

라는 말이 하고싶은것이 아니다.

어디가 잘못된건지 아직도 모르는것이 화가난다

 

 

폐기된 코드에 대한 이야기는 그만 하도록 하자.

 다시 다음 방안으로 넘어가서,

 

 

2. 튜터님의 피드백에 해당하는 내용으로 ,

login 검증 함수를 호출할 당시에, 미리 캐릭터 검증을 포함하는지, 안하는지 정보를 줘서

검증이 필요 없을때는 본래의 코드만, 정보가 있을 때에는 추가 코드를 실행하게 만들어서

각각 온전하게 필요한 부분만 작동이 가능하도록 하는 방법 에 대한 내용이다.

 

이 방법은 내가 당장 이해하기엔 어렵지 않을까 생각이된다.

 

 

 

분노의  TIL 을 작성하다 보니, 오늘 진행한 내용은 결국 작성하지 못했다.

 

다음 시간에 !!

 

 

 

 

 

 

즐거운 토요일... 코딩을 시작해보자.

 

오늘의 목표는 인벤토리를 어느정도 구현해보는 것이다.

 

구현에 앞서서...

인벤토리란 무엇일까?

흔히, '가방' 으로 표현되는 인게임 기능으로, 캐릭터가 항상 들고 다니는 

아이템 보관함 같은것 이라고 할 수 있다.

어플리케이션 마다 인벤토리의 형식은 많은 차이가 있지만,

내가 생각하는 인벤토리의 가장 기본적인 기능은,

 

아이템의 소유자를 명시하는 테이블 이라고 보고 있다.

 

가질 수 있는 아이템의 한계치, 혹은 수량의 중첩 등 부가적인 기능들이 있지만,

기본적으로 어떤 아이템을 '누가' 소유하고 있고, 그 소유자만이 해당 아이템을 사용 할 수 있게 하는것이

인벤토리의 가장 기초적인 기능이라고 생각된다.

 

 

 

그것을 중점으로 생각하여 우선 테이블을 만들어 보았다.

 

inventoryNumber 는 아직 어떤 기능을 할 지 모르겠지만 왠지 필요할 것 같기에 일단 넣어둔 것이고,

 

결국 캐릭터의 Id 와 아이템의 Id만 있다면 아이템의 소유를 명시 할 수 있을것이라 생각하고 만들어봤다.

 

해당 인벤토리 테이블은 서버 내의 '모든' 캐릭터가 소유한 '모든' 아이템을 담게된다.

 

때문에, 인벤토리는 동일한 캐릭터가 여러번 들어갈 수 있어야 하며, 

같은 아이템 또한 여러개의 소지가 가능하기 때문에,

itemId 와 CharacterId를 모두 1:N 관계로 설정했다.

 

이를 통해 만들어진 인벤토리의 모습 

 

여기서 한가지 문제점 (한가지 만은 아닐테지만)을 발견했다....

 

 

현재로서는,

캐릭터의 Id를 특정 할 수가 없는 상태이다.

 

왜냐하면 지금 구현된 부분은, 계정 로그인만 하고 캐릭터는 따로 접속하는 개념이 없기 때문에,

계정 외에는 특정할 수 있는 부분이 없다.

 

해결 방안..?

 

1. 한 계정 당 캐릭터 하나로 제한하여 사실상 캐릭터===계정으로 만들어버린다.

    -> 제작 의도와 거리가 멀기 때문에 탈락

 

2. /api/:character_id/ item~어쩌구 저쩌구

   - 캐릭터 id를 params 로 받는 방법.

   -> 거의 모든 api 에서 해당 character_id가 계정내 캐릭터가 맞는지 검사해야한다.

   -> 유저와 서버와 개발자 모두 별로인 방법

 

3. 로그인 처럼 캐릭터 접속 기능을 만든다.

   -> 지금 생각나는 방법 중에선 가장 그럴싸하다.

 

 

당장 해보자. 

계정 로그인 API 와 캐릭터 삭제 API의 형식이 묘하게 합쳐져서 캐릭터 접속 API 가 되었다.

 

하지만, 문제를 해결하려 할 수록 오히려 문제가 늘어가고 있다...

 

접속에 성공했다면, 해당 캐릭터Id를 어디에 저장해야 할까?

 

쿠키를 두개 쓴다? 제대로 참고할 수 있을지도 잘 모르겠고,

모든 매 통신마다 보내는 쿠키가 하나 더 늘어나는것은 좋지 않은데다가,

 

 

해당 과제 요구사항이 뜻하는 것이 아직 제대로 이해가 되지 않기 때문에

어떻게 해야할지 모르겠다.

 

진전이 없기 때문에, 일단은 지금의 cookie 를 계속 사용하고 나중에 방법을 다시 알아보기로 했다.

 

다시 돌아가...자 마자 문제 발생 !!

 

authMiddleware 가 로그인정보 + 캐릭터 정보 모두 검증하게 만들 계획이었지만,

 

캐릭터 접속을 하기 위해서는 로그인이 되어야 하기 때문에  authMiddleware  검증이 필요하다.

 

마치,

자물쇠가 걸린 방 내부에 자물쇠 열쇠가 있어서 못들어가는것 과 같은 상황이다.

 

해결방안

1. 캐릭터 접속까지 authMiddleware 검증 없이 어떻게든 해결한다??

   -> 캐릭터 접속, 생성, 삭제 등 로그인 만 하면 되는 기능들을 전부 직접 검증해야한다

 

2. 로그인 시 임의의 캐릭터 정보 값을 부여하여, 캐릭터 접속을 가능하게 한다.

   -> 임의의  값 일때 캐릭터 접속 이외의 검증은 통과해선 안되기 때문에

        검증을 필요로 하는 모든 API 에 추가 조건을 만들어야 할듯..

 

3. authMiddleware 를 2가지로 나눈다 !! (계정 검증 / 계정+캐릭터 검증) 

  -> 정말 내키지 않는 방법인데 일단 이 방법이 그나마....

 

 

생각해보면 

로그인만 해도 가능해야하는 API (캐릭터 생성, 캐릭터 접속, 캐릭터 삭제) 와 

캐릭터 접속까지 해야 가능한 API 어느정도 분리되어야 하기 때문에,

authMiddleware 2가지로 나누는게 아주 나쁜 선택은 아닐것이다.

( 평일이 되면 관련 내용을 튜터님에게 피드백 받아보자 )

 

어렵진 않으니 만들고보자.

 

그냥 복붙으로 두개로 나눈다음에, 필요한 곳에서 각각 불러오고, 적용하면 끝이다.

 

캐릭터 접속까지 한 경우를 검증하는 connect.auth 에서는

추가로 char 값이 이상할 때 에러를 발생하게 하면 된다.

 

이 작은 차이 때문에 복사를 해야한다고?! 생각이 되긴한데 다른 방법이 당장 떠오르지 않는다..

 

 

 

캐릭터 접속까지 요구하는 API
캐릭터에 접속
접속 후 동일한 API가 잘 처리된 모습

 

 

이 타이밍에..... 엄청난 반전이 있었으니...

 

 

 

 

이럴수가 ...?!?!?!?

 

 

도전기능

에 해당하는 부분에서, 캐릭터ID 를 param 으로 받는다는 내용이 기재되어 있었다...

 

필수 과제만으로 벅찰것 같아서 자세히 확인을 안해본 도전과제에

저런 내용이 있었다니 !!

 

사실 이는 해당 글의 상단에 있는

 

 

2번 해결방안에 해당하는 내용이었다.

그 해결 방안이 과제에서 제시한 방법이었던 것이다.

 

음.. 별로인.. 방법 아닐지도 ? ㅎ

태세 전환

 

 

 

 

 

 

시작에 앞서서, 어제 문제가 됐던 부분을 다시 살펴보자.

 

 

이번에 사용한 방법은, findFirst를 where 까지만 우선 실행해서,

character.userId 를 얻어내는 방법이다.

 

그 다음 한번 더 find 하는 효율적인 작업을 해서, 

Money에 삼항 연산자를 적용하는 방법이다.

 

 

의도한 대로 작동하지만, 조회 한번 하는데 쿼리를 3번이나 불러오는 현상이 목격되었다.

where 로 2번, select 로 한번 불러 오는 듯 하다.

 

 

음...

character.userId 를 참조하는 쉬운 방법이 분명히 있을것 같은데,

상당히 기초적인 것을 놓치고 있는 느낌이다.

그게 아니라면, where 와 select 사이에서 뭔가 해 줄 수 있을것 같은데, 아직 잘 모르겠다.

 

 

 

 

우선 어제 계획한대로, 강의 부터 모두 듣고난 뒤에 

계속해서 과제를 진행해 보았다.

 

 

오늘 진행한 부분은 아이템 관련 부분이다.

 

위의 아이템 생성 API 는, 로그인 없이도 아무나... 만들 수 있으며,

만들어진 아이템은 items에 추가된다. 

 

items 테이블

 

 

 

조회 기능도 만들어 보았다.

마찬가지로 아직 error 잡는 부분 등은 미흡

 

itemId 2의 상세 조회 결과

잘 작동하는 모습 !!

 

오늘 구현한 기능은 많지 않지만, 

강의를 모두 들었기 때문에 다음 주 부터는 조금 더 속도가 날 것 같다.

 

 

 

 

 

 

CH 3 아이템 시뮬레이터 과제 !

 

아직 강의를 다 듣지 못했지만

조금 급한 마음으로 과제를 시작해보았다.

 

내가 할 수 있는게 맞는지 아닌지가 궁금했기 때문이다.

 

 

 

강의를 토대로 만든 결과 나름대로 잘 작동하는 모습이다 !

 

아직 error 처리라던지,  디테일한 DB 셋팅 등등  할 일이 많지만...

 

그래도 못할 건 없겠다 라는 생각이 들어서 안심이 됐다.

 

 

그래서.. 

 

오늘의 문제 !!

 

 

캐릭터 조회 API 만들기 ..

 

우선, params 를 입력받아 해당 캐릭터Id를 조회하게끔 구현을 해 보았다.

 

문제는 캐릭터 조회가 아니라...

 

바로 이 두 줄에 해당하는 부분이다.

 

 

 

 

아무리 생각해도, 로그인했을때  기록된  userId 와,

현재 조회하는 character 가 가진 userId 가 같은지를 비교하는게 맞는 방향 같은데,

 

로그인 했을 때 userId 는 req.user 가 가지고 있고,

문제는 조회한 character 가 가진 userId 인데,

 

방법을 모르겠다.

방법을 왜 모르는지 모르겠다 !!

 

위에 코드는,

일단 userId를 select 하고  그 select 한 userId를 토대로 비교해서 

Money를 삭제할지 말지 정하는 if문을 추가한 방식이다.

 

문제가 되는 사항은,

userId는 조회 할 필요가 없다.

그래서, userId를 셀렉트 하지 않으면? 

아래 if 문에서 userId를 참조할 수가 없게된다..

userId select를 : false 로 바꾸면?

 

그럼 애초에 select 하지 않아서인지, 참조가 되지 않는다.

 

 

사실, 이 단계까지 오는데도 너무 오랜 시간이 소요되었기 때문에...

수리를 할 시간이 부족했다.. 

이미 자정이 지나버린 시간

 

 

결국,

userId 까지 select 하면 아무튼 의도대로 작동하는 상태

에서 마무리가 되었다. 수리는 좀 나중으로 미루고...

 

 

내일은 조급한 마음을 가라 앉히고 다시 강의를 듣는것에 집중해야겠다.

 

저번 시간에 배운 1계층 - 물리 계층에 이어서,

오늘은 2계층인 데이터 링크  계층에 대해 알아보자.

 

 

데이터 링크 계층 (Data Link Layer)

OSI 7 계층 중, 2계층에 해당하는 내용으로,

- 직접 연결된 서로 다른 2개의 네트워킹 장치간의 데이터 전송을 담당

- Network 장비 간에 신호를 주고받는 규칙을 정하는 계층

- Network 기기 간에 Data를 전송 + 물리 주소를 결정

- 장치 간 신호를 전달하는 물리 계층을 이용해서, 네트워크 상의 주변 장치들 간에 Data를 전송

- Data들을 Network 전송 방식에 맞게 단위화 해서, 해당 단위를 전송

  .. 이때 전송되는 Data를 Frame 이라고 함 !

- Data Link Layer 에서 최종적으로 이더넷 헤더/ 트레일러가 붙는다.

 

 

주요 기능

프레이밍 (Framing)

- 물리 계층으로부터 받은 신호들을 조합해서 프레임(Frame) 단위의 정해진 크기의 Data Unit으로 변환

 

오류 제어 (Error Control)

- Frame 전송 시 발생하는 오류들을 처리

 

흐름 제어 (Flow Control)

- 송수신 측 간에 Data를 주고 받을 때, 적당한 양의 Data를 송수신 할 수 있도록 Data의 흐름 제어

 

접근 제어 (Access Control)

- 매체 상에 기기가 여러개 존재할 때, 데이터 전송 여부를 결정

 

동기화 (Synchoronization)

- 수신 노드에서 데이터 시작을 알 수있도록 송신 노드가 헤더 부분이 시작되기 전 일정한 비트 패턴 (Frame 구분자)

를 첨가하여 동기화 한다.

 

 

이더넷 (Ethernet)

- LAN 환경에서 Data 를 정상적으로  주고받기 위한 규칙

- Data 충돌을 막기 위해 CSMA / CD 프로토콜을 사용

- 현재에는 UTP 케이블 및 광케이블을 사용

- 프리앰블 / 이더넷 헤더 / Layer 3패킷 / FCS 를 추가해서 Frame 생성

 

 

 

데이터 링크 계층의 링크 종류

Point - to Point 방식 

- PPP, Ethernet 스위치와 호스트 사이의 Point  to Point 

 

Broadcast 방식

- 매체를 공유하는 방식으로 케이블형 Ethernet, 무선 LAN 이 해당

 

 

MAC 주소 (Multiple Access Control)

MAC 주소는 데이터 링크 계층에서 사용하는 주소로, 하드웨어의 생산 당시에 찍혀서 생산되기 때문에,

변경할 수 없는 물리적인 주소이다. MAC 주소는 중복될 수 없고, 한개의 기기에 한개의 MAC 만 존재한다.

 

 

 

입문주차를 끝내고, Node.js숙련 주차에 해당하는 강의 ! 

 

에 대한 이야기를 하기에 앞서서,

 

CH3 의 개인과제에 해당하는 내용이 오늘 공개가 되었다.

과제의 발제 자체는 내일이지만, 어쨌든 해야할 과제가 무엇인지는 공개가 되었다.

 

그 과제는 이름하야...

 

CH 3 아이템 시뮬레이터 과제 !!!

 

 

학습 과제를 끝내고 나면 할 수 있어요!  ==> 이걸 모르면 과제를 할 수 없어요 !

 

발제는 내일이기 때문에 간략하게만 살펴 보았는데,

 

Expreess 로 서버 와 api 구성

AWS RDS -> MySQL 을 사용하여 데이터 베이스를 활용

Prisma를 사용하여 데이터 베이스 컨트롤

AWS EC2 를 이용한 배포

 

와 같은 내용으로 구성되어 있었으며

 

조금 더 구체적으로 들어가면,

1. 회원가입 및 로그인 기능

2. 캐릭터 생성 및 캐릭터의 능력치 설정

3. 캐릭터 상세 조회와 캐릭터 삭제 기능

4. 아이템 생성 

5. 아이템 수정 (강화..?)

6. 아이템 목록 조회 및 아이템의 상세정보 조회

 

도전기능으로는 

1. 아이템 구매 및 판매

2. 인벤토리 기능

3. 장착 아이템 목록 조회

4. 아이템 장착 및 탈착 API

5. 게임머니 획득 API

 

 

이걸 만들라구요 ?!

 

 

어라... 이 감정...?

 

24.08.21 TIL - Roglike 과제를 받은 날

 

 

그렇지만 이번에는 정말로 어려울것 같다는 느낌이 든다...

따로 스켈레톤 코드 같은 것이 지급되지 않는것으로 확인이되어,

더 감이 안잡히는것 같다.

 

 

중요한건 강의를 서둘러서 들어야 한다는거임

 

관계형 데이터베이스 

 

오늘 배운 내용은 전부 여기에 해당한다고 볼 수 있다.

 

저번시간에 학습했던 비관계형 데이터베이스인 mongoDB 와 달리

관계형 데이터 베이스에 해당하는 Mysql을 기반으로 학습을 진행했다.

 

 

관계형 데이터 베이스에 해당하는 Mysql 은 이전에 입문단계에 해당하는 강의를 학습한 적이 있다.

때문에 비교적 이해하는데 큰 어려움은 없었다.

 

차이가 있다면, 입문강의에서 진행했던 내용은  DBeaver 를 통해 이미 작성된 database 를 조회하는

방법 위주로 강의가 진행되었기 때문에, 내용을 따지고 보면 오늘 학습하는 내용과 차이가 꽤 크다고 볼 수 있다.

 

오늘은, 실제로 MySQL 데이터베이스를  AWS RDS 를 통해 직접 구동하여 (대여해서...)

Database 와 table, 그리고 column 에 해당하는 부분을 직접 추가하거나 수정하고, 삭제하는 과정을 학습했다.

VScode 에서  SQL 언어을 사용할 수 있고, 

MYSQL 확장 프로그램을 통해 VScode 내에서 사실 다 할 수 있다.

마이크로 소프트.. 그는 대체...

 

 

 

 

오늘 미약한 공포가 느껴졌던 부분

그것은 바로 Raw Query 라고 할 수 있다.

언뜻 보면, 노드 환경에서 직접 SQL 요청을 보내는 평범한 기능으로 생각이 되지만, 

 

// app.js

/** 테이블 생성 API **/
app.post('/api/tables/', async (req, res, next) => {
  const { tableName } = req.body;

  await connect.promise().query(`
      CREATE TABLE ${tableName}
      (
          id        INT         NOT NULL AUTO_INCREMENT PRIMARY KEY,
          name      VARCHAR(20) NOT NULL,
          createdAt DATETIME    NOT NULL DEFAULT CURRENT_TIMESTAMP
      )`);

  return res.status(201).json({ message: '테이블 생성에 성공하였습니다.' });
});

 

이런식으로 Raw Query 를 작성하다 보면, 이건 좀 아닌것 같다는 생각이 스멀스멀 들기 시작한다.

 

강의에서는 Raw Query 최대 단점을, 유지보수가 어려운 점을 꼽았는데,

예를 들면,

createdAt 라는 칼럼이  createDate 라는 칼럼명으로 바뀌어야 한다고 가정해 보자.

우리는 Raw Query로 작성한 createdAt를 전부 찾아서 createDate 로 수정해야만 할 것이다.

 

그냥 바꾸지 말죠? 에서 부터,

최악의 경우, 한 두가지를 놓치는 바람에 서버가 다운되거나 데이터가 변조될 위험성도 있다.

 

ORM  등장 (Object Relational Mapping) 

 

앞선 문제들에 대한 대책으로 ORM이 개발되었고, 강의에서는 ORM 중 하나인 Prisma 를 소개해 주었다.

 

 

 

 

ORM 의 최대 장점은, 데이터 베이스가 통째로 바뀌더라도 유연한 대처가 가능하며, ( ex MySQL -> Oracle)

위에 언급된 문제인 Table 또는 cullum 의 수정 정도는 어렵지 않게 대처할 수 있다.

 

 

Node에서 Prisma를 설치할 경우,

schema.prisma 을 내용을 토대로 database 를 추가하거나 수정할 수 있게 된다.

Posts 라는 새로운 table 과 각 cullum 의 설정을 작성한다.

 

SQL 과 Raw Query 사이 어딘가....로 보이는 형태의 언어이지만,

성능이 확실하다고 설명했기 때문에 왠지 호감도가 올라간 상태 !!

 

이렇게 schema.prisma에 작성한 내용을 

 

 npx prisma db push 명령을 통해 push 하면,

 

 

node_modules/.prisma/index.d.ts  의 어딘가에

JS 형태로 작성이 되어진다.

(이 외에도 예상했던것 보다 많은것이 기록된다...)

 

 

 

Prisma를 통해 Posts table과 각 컬럼 속성 설정에 성공한 결과 !

 

 

오늘 학습한 내용은 여기까지 인데, 아무래도 과제 발제 까지 시간이 촉박 하기 때문에,

 

며칠정도는  TIL 의 작성시간을 줄이고 강의를 더 듣는다거나, 

주말을 포기한다거나 하는 일이 발생할 것 같다...

 

 

 

 

 

어제에 이어서 2주차의 마지막이자, 입문주차의 마지막 부분을 학습했다.

 

범위로만 따지면 2.9~ 2.11에 해당하는 부분이라 금방 끝날 것으로 예상하고

오늘 숙련주차를 들어갈까 말까를 생각했었는데,

 

입문주차 마무리를 겨우 할 정도로 빠듯했다.

 

 

2.9 코드 서식 정리하기

에 해당하는 부분은, 이전 과제에서 Prettier 를 간단하게 다루고 넘어갔기 때문에 

어느 정도는 알고있던 부분이다. 

{
    "printWidth": 50,
    "tabWidth": 4,
    "singleQuote": false,
    "trailingComma": "es5",
    "semi" : false,
    "arrowParens": "always"
  }

나름대로 원하는 스타일로 prettierrc.json 을 작성 해 보았다.

singleQuote 부분은 기본적으로 single을 사용할 예정이지만,

한글이 포함되거나 포함될 가능성이 있는 문자열만 "" 을 사용해보려고 한다. (최소한의 개성..?)

물론 변동될 수 있지만 말이다

 

 

 

2.10 배포를 위한 Git 학습 

또한 이전 과제와 그 전에 해당하는 최초의 과제를 진행하며 어느정도 학습한 부분이 있다.

다만, 이전에는 Github Desktop 라는 최신식(?) 사용자 친화적 인터페이스를 갖는 보조도구를 사용했기에

이번에는 강의에 나온 것 처럼 터미널을 이용하여 Git 과 연동하는 작업을 해 보았다.

 

 

 

Github desktop가 알아서 처리해줬던 부분인,

Git 명령어를 먼저 알아보았다.

 

 

 

 

간단하게, 이미 알고있던 desktop 의 방식과 비교하며 정리해볼까? 

 

 

git init 은 현재 위치한 경로를 git repository로 지정하는 명령어 이다.

GUI 에서는 create new repository를 통해 init 기능을 사용할 수 있다. 

(디렉토리를 지정하여 새로운 레포지토리 생성)

아마 Add local repository도 비슷한 기능인듯 하다.

오히려 이쪽에 가까울지도?

 

변경 사항을 스테이징 영역에 올리는 명령어로..

이 부분은 아마 Github desktop를 이용한다면 스킵되어버리는 명령어로 확인이 되어진다.

뭔가 생소한 기능인것 같아서 검색을 해보니, Github desktop 에서는 commit 과 동시에 add가 이루어진다 

라고 설명하는 경우가 많다.

 

개인적으로는 gui의 인터페이스에서

레포지토리로 지정한 폴더의 모든 파일이 자동으로 add 된다는 느낌이긴 한데 맞을지 모르겠다.

(일단 모든 파일이 add 되고, 커밋을 할지 ignore 할지 결정하는 느낌?)

 

 

 

깃의 대표적인 기능중 하나로, 변경사항을 기록하는 것이다.

이 시점으로 얼마나 내용이 수정되었는지, 등록이 되기 때문에 

원한다면 등록했던 많은 커밋 중 하나의 시점으로 파일을 복원하는것이 가능하며,

추가적으로 코멘트를 달아서 해당 커밋의 내용을 직관적으로 설명할 수 있다.

저지른다

 

 

 

본격적으로 git과 github 를 연결하는 명령어로, 

정확히 말하면 로컬 저장소에 원격 저장소를 추가하는 기능이라고 설명되어있다.

commit, push 한 데이터가 어디로 날아갈지 지정하는 명령어 이다.

 

Github desktop 에서는 첫 레포지토리 생성 후

commit 등 원격 저장소를 필요로하는 작업을 하기 전에 

Publish resository를 통해 지정하게 되어있다.

github desktop 에 로그인된 github 계정에 자동으로 연결된다.

 

 

 

클론으로 repository를 생성한다면, 

클론 할 원격 저장소의 주소가 바로 필요하기 때문에, 시작과 동시에 

입력을 하게 되어있다.

git clone 과 remote add 기능이 합쳐졌다고 보면 될 듯 하다.

 

push 는 commit 한 내용을 본격적으로 원격 레포지토리에 업로드 하는 명령어 이다.

 

GUI 에서는 commit 을 하면, 자동으로 push 를 진행하는 버튼이 활성화 된다.

 

 

 

 

push 가 업로드 라면, pull 은 다운로드 라고 할 수 있다.

원격 저장소에 push된 최신 변경사항들을  로컬 저장소로 가져오는 작업을 말한다.

GUI 에서는 해당 명령을 통해, 아직 적용되지 않은 최신 사항을 체크 할 수 있으며,

있을 경우 pull 버튼이 활성화 되어, 비교 및  적용이 가능하다.

 

 

 

2. 11    AWS 배포하기 

오늘 가장 난해했던 부분이다.

 

이전 강의를 통해 만든 서버를 본격적으로 배포하기 위한 수단으로...

기본 사양의 서버인 EC2 에 해당하는 서버를 1년 동안 무료로 사용할 수 있는

대인배  클라우드 서비스 라고 할 수 있다. (물론 프리티어라도 막쓰면 1년 내에 요금이 나올수도 있다)

 

 

강의에서 알려주고는 있지만, 기본적으로 사용한 만큼의 요금이 발생하는 유료 서비스 이며,

잘못 사용 할 경우 금전적인 문제 또는 정보 유출 등의 문제가 발생할 수 있기 때문에, 

추가적으로 알아보고 조심조심소심소심; 하며 진행했고....

시간을 많이 잡아 먹었다 ! !

 

아무튼간에 회원가입과 EC2 인스턴스의 생성은 마쳤고,

 

 

pm2 를 활용하여 app.js 를 구동하는것도 성공했다.

 

웹 브라우저로 접근했을때도 정상적으로 작동하는 모습 !!

위에 보이는 5252 는, 같은 조원이 해당 페이지에 접속해서 남긴 글이다. 

다른 사람도 접근이 가능한것을 확인 !

 

 

pm2 log를 통해 로그도 정상적으로 확인 가능하다.

 

 

여기까지 봤으면 그래도 오늘 할 일은 다 한듯 하다..

 

 

 

+ Recent posts