What is VPC

VPC 란 Virtual Private Cloud 의 약어로 사용자가 모든 AWS 자원에 대한 Access Control 이 가능한 private network 입니다.

즉, 사용자는 VPC 안의 Internet Gateway, Route Table, Subnet 등 다양한 네트워크 리소스를 마음대로 제어할 수 있으며 자신의 네트워크에 접근할 수 있는 사용자들에 대한 권한설정이 가능합니다.

다음 그림은 AWS 의 VPC 를 시각적으로 표현한 도식입니다.

Screen Shot 2019-04-20 at 4.40.45 PM

아마존에는 수많은 region 이 존재하며, 이는 전 세계에 분포되어 있으며, 각 지역별 가용한 zone 을 Availavility Zone 이라고 부릅니다.

사용자는 여러 availability 존에 분산하여 리소스를 운영함으로써 aws 에 지역적인 결함이 생겨도 문제없이 서비스를 운영할 수 있습니다. VPC 는 이러한 여러 Region 을 모두 포괄하는 개념입니다.

VPC를 세팅함에 있어 다음과 같은 순서로 진행합니다.

  1. Choosing IP Address
    VPC 는 네트워크로써 외부에서 접근하기 위한 IP 주소를 가지며, 내부 ip를 사용합니다.
    사용할 내부 IP의 범위를 설정하며 이는 CIDR 표기법으로 작성합니다.
  2. Routing Table 을 설정합니다.
    VPC 내부에서 외부로 자원을 요청할 때, VPC 는 외부 주소를 확인해야 합니다. 이처럼 외부 주소를 라우팅 해주는 Route Table 이 필요하며 Routing Table 은 외부 요청에 대한 Routing 을 담당합니다.
  3. Security Group
    각 VPC 에는 여러 개의 Security 그룹을 가질 수 있으며, VPC 내의 리소스 마다 해당 VPC에 종속되는 Security 그룹을 할당합니다.

Choosing IP Address

사용할 내부 IP 의 범위를 설정합니다.

Screen Shot 2019-04-20 at 4.42.00 PM

Routing Table

아래와 같이 요청을 Route 해줄 Routing Table 을 설정합니다. 네트워크 외부로의 요청에 대한 Routing 을 담당합니다.

Screen Shot 2019-04-20 at 4.44.39 PM

해당 VPC 의 모든 내부 ip 는 local 로 routing 하며 그 외의 모든 주소에 대해서는 Internet Gateway 에 요청을 전달하고 적합한 목적지로 요청을 Routing 해줍니다.

Setup Subnet

요청에 대한 접근 관리는 Security Group 설정으로 관리됩니다.

Screen Shot 2019-04-20 at 4.47.21 PM

위 그림에서 위의 4개의 인스턴스는 웹 서버를 의미하며, 아래의 세개의 인스턴스는 웹 서버에서만 접근이 가능한 private resource 입니다.

각 subnet 은 vac 의 서로 다른 내부 ip range 를 할당하여 가상으로 다른 네트워크로 분리합니다.

이 경우 두개의 resource 를 각각 public subnetprivate subnet 으로 나누어 관리할 수 있으며 각 subnet 마다 다른 security 그룹을 할당하여 접근을 관리할 수 있습니다.

##

Outbound request in VPC

아래와 같이 외부로의 요청을 처리하는 NAT 는 VPC 의 내부 ip range 로의 모든 요청을 VPC 내부로 Route 하고 그 외의 모든 요청을 NAT Gateway 를 통한 외부접근으로 설정한다.

Screen Shot 2019-04-20 at 4.55.35 PM

Hyperledger fabric 시작하기

Prerequisition

  1. docker 설치하기
  2. virtual box 다운로드

VM 환경 설정

먼저 다음 명령어를 통해 docker를 사용하기 위한 VM을 생성해 줍니다.

1
docker-machine create --driver virtualbox blockchain

새로 생성된 VM의 환경변수를 Host에 적용해 줍니다

1
docker-machine env blockchain

운영체제에 따라 다음과 같은 명령을 실행해 줍니다.

MacOS

1
$ eval $(docker-machine env blockchain)

Windows

1
@FOR /f "tokens=*" %i IN ('docker-machine env blockchain') DO @%i

Docker 사용을 위한 환경 설정이 잘 되었는지 확인합니다.

1
docker images

Download hyperledger fabric docker image

다음의 명령을 통해서 모든 이미지를 받습니다.

1
2
3
docker pull hyperledger/fabric-baseimage:x86_64-0.2.2
docker pull hyperledger/fabric-membersrvc:x86_64-0.6.1-preview
docker pull hyperledger/fabric-peer:x86_64-0.6.1-preview

이미지를 다 받으셨으면 docker images 명령을 통해서 이미지 리스트를 확인합니다.

1
docker images

baseimage의 경우 Tab를 latest로 태깅을 해야 합니다. 향후 블록체인의 운영모드에서 체인코드 디플로이를 할 경우 baseimage를 통해 체인코드 구동을 위한 Docker 이미지를 만드는데 hyplerledger/fabric-baseimage:latest 를 사용합니다.

1
2
docker tag hyperledger/fabric-baseimage:x86_64-0.2.2 hyperledger/fabric-baseimgae:latest
docker images

docker configuration

Docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
membersrvc:
image: hyperledger/fabric-membersrvc:x86_64-0.6.1-preview
ports:
- "7054:7054"
command: membersrvc
vp0:
image: hyperledger/fabric-peer:x86_64-0.6.1-preview
ports:
- "7050:7050"
- "7051:7051"
- "7053:7053"
environment:
- CORE_PEER_ADDRESSAUTODETECT=true
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=vp0
- CORE_PEER_PKI_ECA_PADDR=membersrvc:7054
- CORE_PEER_PKI_TCA_PADDR=membersrvc:7054
- CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054
- CORE_SECURITY_ENABLED=true
- CORE_SECURITY_ENROLLID=test_vp0
- CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT
links:
- membersrvc
command: sh -c "sleep 5; peer node start --peer-chaincodedev"

Fabric 소스 준비하기

컴퓨터의 go path 내에 hyper ledger-fabric 의 코드를 받습니다.

1
2
3
4
5
mkdir -p $GOPATH/src/github.com/hyperledger
cd $GOPATH/src/github.com/hyperledger
git clone https://github.com/hyperledger/fabric.git
cd fabric
git checkout v0.6.1-preview

우선 예제 코드를 빌드하여 블록체인 네트워크 상에서 동작을 확인해 봅시다.

MacOS

1
2
cd $GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
go build

Windows

1
2
cd %GOPATH%\src\github.com\hyperledger\fabric\examples\chaincode\go\chaincode_example02
> go build

위의 과정을 문제없이 완료하였으면 chaincode_example02 디렉토리 하위에 chaincode_example02 라는 이름으로 실행파일이 생성되었을 겁니다.(Windows는 chaincode_example02.exe ) 개발모드에서는 이 실행파일을 몇 개의 환경변수와 함께 실행하기만 하면 블록체인 런타임에서 트랜잭션 테스트가 가능한 상태가 됩니다.

스마트 컨트랙의 배포

체인 코드를 validating peer 컨테이너에 복사해 넣고 rest api로 deploy만 호출하면 블록체인 네트워크 전체에 코드가 적용됩니다.

다음은 운영모드에서 어떻게 체인크도그 반영되는지를 보여줍니다.

체인코드의 디플로이 프로세스

  1. 운영모드에서 체인코드 디플로이가 요청되면 요청을 받은 Peer는 블록체인 네트워크상에 연결되어 있느 모든 피어에게 동일한 체인코드를 전송합니다.
  2. 체인 코드를 받은 각 validating peer는 체인코드르 빌드하여 체인 구동을 위한 docker-image를 만들고, 실행하게 됩니다.
  3. validating peer는 docker remote api서비스에 체인코드를 위한 docker-image 생성 및 실행을 요청하고 docker-engine은 hyper ledger/fabric-baseimage를 이용하여 체인코드 docker이미지를 생성하고 실행합니다.

Validating Peer의 수정

docker machine은 VM 환경을 만들 때 기본적으로 https 통신을 하도록 docker 엔진을 구동하고, validating peer 가 docker engine api 에 요청하기 위해서는 블록체인의 ssl certificate를 가지고 있어야합니다.

이렇게 validating peer 가 ssl certificate를 가지기 위해 다음과 같은 절차를 거칩니다.

  1. 실행중인 validating peer 컨테이너에 certificate들을 복사합니다.
  2. 실행중인 Validating Peer 컨테이너에 터미널로 접속해서 설정파일을 수정합니다.
  3. Validating Peer에서 빠져나와서 실행중인 Validating Peer 컨테이너를 새로운 이미지 명으로 commit 합니다.
  4. 새로 생성된 이미지로 Validating Peer를 다시 구동합니다.

컨테이너에 ssl 인증서 복사

1
2
3
4
5
컨테이너에서 로컬로 복사
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

로컬에서 컨테이너로 복사
docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH

인증서 위치

1
2
3
$ cd $HOME/.docker/machine/machines/blockchain
$ mkdir key
$ cp {cert,ca,key}.pem key

도커 컨테이너 아이디 확인

1
docker ps

컨테이너에서 Peer의 설정파일에 인증서 위치를 명시

1
2
3
4
docker exec -it 컨테이너ID bash

위 그럼을 기준으로 명령 예는 다음과 같습니다.
docker exec -it 4409df7072c4 bash

docker의 bash 에 접근하였으면 다음과 같은 설정파일을 수정한다.

1
2
 cd membersrvc
# vi membersrvc.yaml

What is the RESTful API

Rest API 란 WWW 과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식으로 자원을 정의하고 자원에 대한 주소를 지정하는 방법 전반에 대한 패턴이다.

좀 더 쉽게 말하자면, REST API 란 인터넷이라는 정보의 바다에서 정보를 주고받는 활동을 인터넷에 있는 자원과 자원의 위치를 명시 하는 일종의 방법론이자 아키텍처이다. API 설계의 핵심은 자원을 사용하는 것이고 HTTP method 를 통해 자원을 처리하는 양식을 일컷는다.

Characteristics of REST API

  1. Uniform Interface
    URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행합니다.
    이는 REST API 의 핵심이며, 자원과 자원에 대한 행위(HTTP method) 를 명확히 구분하고 준수합니다.

  2. Stateless
    REST 는 상태를 가지지 않습니다. 즉, 작업을 위한 상태 정보를 저장하고 관리하지 않기에 서버는 들어오는 요청만 단순히 처리하면 됩니다. 이를 통해 구현이 간편해 집니다.

  3. Cacheable
    HTTP라는 기존 웹표준을 그대로 사용하기 때문에, Http가 가진 캐싱 기능을 사용할 수 있습니다.
  4. Self descriptiveness
    REST API uri 만 보고도 이를 쉽게 이해할 수 있는 자체 표현구조로 되어있습니다.
  5. Client-Server 구조
    자원을 제공자인 Server 와 사용자인 Client 가 명확히 구분되기에 의존성이 없습니다.
  6. 계층형 구조
    REST 서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수 있게 합니다.

How to design RESTful API

REST API 설계시 가장 중요한 항목은 다음 두가지로 요약할 수 있습니다.

  1. URI 는 정보의 자원을 표현해야 한다.
  2. 자원에 대한 행위는 HTTP method 로 표현한다.

즉, URI 는 어떤 자원을 사용할지에 대한

What is the object oriented programming

객체지향 프로그래밍 이란 그 이전의 프로그래밍이 컴퓨터가 하는 동작 즉, 명령 단위의 프로그래밍을 벗어나 인간이 사고하는 방식 그대로를 표현할 수 있는 방식으로 프로그래밍을 하는 프로그래밍 패러다임을 의미한다.

객체지향 프로그래밍 에서는 실제 생활의 행동과 사물 그대로를 프로그램 상에서 표현하며 모든 프로그래밍은 이러한 ‘객체’ 를 기반으로 움직이게 된다. 여기서 객체라 하면 속성(attributes) 과 행위(method)를 가지는 일종의 데이터이다.

이러한 객체지향 프로그래밍에서는 코드 재사용성과 확장성을 위해 상속(inheritance) 이라는 개념이 존재하는데, 이는 class 와 prototype 의 형태로 나타난다.

먼저 class based language 에서는 object 보다 항상 class 가 먼저 정의되어야 하며, object 는 이러한 class 를 통해 생성된다. Class 를 통해 instantiate 된 객체를 instance 라고 하며, 이렇게 생성된 instance 는 class 의 속성에 따라 일관된 방식으로 통제될 수 있다. 이러한 class based language 에서는 특정 class 를 inherit 하여 코드 재사용성과 확장성을 늘릴 수 있는데, 이렇게 상위 class 를 inherit 받아 새로운 class 가 생성되면, 상위 class 를 super class 상속받은 클래스를 subclass 라고 부른다.

prototype-based language 에서는 class 라는 개념이 없으며, prototype 이라는 개념을 통해 object 자체를 복사하고 확장한다. 가령 javascript 와 같은 언어들이 이러한 갈래에 속하지만 시간이 지남에 따라 javascript 에서도 class 를 지원하면서 그 성격이 변화하고 있다.

이러한 객체지향 프로그래밍의 장점은 재사용성이 매우 높다는 것이다, 특정 객체가 수행하는 역할과 특성을 명확하게 규정해 놓으면 다른 개발자들은 해당 객체를 간편하게 가져다 쓸 수 있다. 이는 프로그램의 기능인 도메인 단위로 객체들이 잘 나뉘어 있기 때문이며, 가령 함수의 이름이나 클래스의 이름만으로도 해당 객체의 특성을 손쉽게 유추하고 사용할 수 있는 특성이 있다.

하지만, 이러한 OOP 에도 단점이 존재하는데, 아는 procedural program 에 비해 코드라인이 길고 특정 기능을 수행하기 위해 많은 명령어가 수행되기 때문에 상대적으로 성능이 좋지 않은 부분이 있다.

또한, 각 개체가 저마다의 상태를 가지기 때문에, 예상치 못한 상태의 불일치로 예측할 수 없는 상태를 가지게 되는 경우가 있어 어플리케이션 내부에서 버그를 가지는 경우가 있다. 이를 해결하기 위한 방안으로 functional programming 이 대두되고 있는데, 그 핵심은 바로 모든 기능을 수학적 함수로 계산하는 것으로 취급하여 최대한 상태변화 혹은 mutable data 를 변경하지 않는 것을 원칙으로 한다. 가령, 함수형 프로그래밍 에서는 pure function 이란 개념을 매우 중요하게 여기는 데 이는 같은 입력값을 주면 항상 같은 결과가 나오는 함수로 전역 변수나 혹은 특정 시스템의 상태에 좌우되지 않는 pure 한 함수를 의미하고 이러한 pure function 은 시스템의 안정성을 높여주는 핵심적인 역할을 한다.

SASS marketing tactic

  1. free tool, educational content
  2. free trial
  3. Identify ideal customer who is the actual customer
  4. SEO, content marketing
  5. collect email(by register in homepage)
  6. live chat

B2B marketing

  1. Quora 에서 질답하며 인사이트를 확보하고 고객의 비즈니스를 이해한다.

  2. 커뮤니티, 포럼에 참석한다.

    inbound.org, growthhackers.com

    Hackers new, insidehackers

  3. 링크드인과 페이스북 그룹을 통해 기업 관계자들과 친분을 쌓는다.

  4. 슬랙 커뮤니티에 활동하라

  5. 다른 브랜드와 협업하라

What is PyQt?

Qt 란 GUI 크로스 플랫폼 프레임워크로 운영체제에 관계없이 같은 코드로 동작하는 프레임워크이다.

PyQt 는 이러한 Qt 프레임워크의 python 바인딩이다.

Qt Designer 는 WYSIWYG(What You See Is What You Get) 방식의 간편한 디자인 툴도 제공한다.

Basic Usage

QApplication.exec() 은 qt 어플리케이션을 시작하고 event loop 에 진입시킨다.

OCX

Object linking and embedding Custom Control 의 약어로 모듈화된 파일이다.

Building node API server based on DDD architecture

Domain Layer

Domain 레이어는 각 서브 도메인 마다 model, service, repository를 가지며 다음과 같은 역할을 수행한다.

- Model

​ 해당 도메인의 모델링이 정의되고, 해당 도메인 내에서의 항상성과 유효성을 담당한다.

- Service

​ 주로 여러 도메인을 아우르는 로직을 처리한다.

- Repository

​ 도메인 단위로 DB 입출력을 담당하며, 실제 구현은 infra layer의 repository implementation에서 이루어 지며, interface만 정의되어 있다.

API Layer

도메인의 서비스들을 조합하며 엔드 유저 레벨에서의 기능수행이 이루어 진다.

가령 특정 재화를 구매함에 따라 결제를 수행하는 어플리케이션이 있다면 본 api 레이어에는 ‘결제’와 같은 엔드 유저 레벨에서의 함수가 들어가며, 결제 데이터 생성, 구매자의 감소 등과 같은 로직은 도메인의 모델 및 서비스 레벨에서 처리된다.

Infra layer

도메인의 비즈니스 로직들이 잘 수행될 수 있도록 DB, http 라우터 등 외부 환경을 다루는 실제 구현이 이루어 진다.

본 레이어에서 도메인의 repository interface에 정의된 함수들을 실제로 구현하며, express router를 활용하여 외부 요청에 대한 라우팅을 수행한다.

또한 본 레이어에는 middleware, auth guard, errorHandler 처럼 도메인에 접근하기 전에 전처리되거나 비즈니스 로직 이후 클라이언트에게 반환할 반환값에 대한 후처리 로직이 들어간다.

auth guard 는 decorator 를 사용하여 제작되었다.

Branching Model

모든 작업 내용은 feature/[브랜치 명] 에서 작업하고, dev 서버에 배포하기 위한 버전을 develop 브랜치에 푸시한다.

Release 브랜치에서 develop 브랜치를 pull 하면서 코드리뷰를 진행하고 모든 코드리뷰 사항이 반영되면 release 브랜치에 머지된다.

release 브랜치에서 스프린트 및 일정관리, 테스트 작업을 진행하며 안정화되면 master 브랜치로 push 하고 서비스 배포한다.

- Master: 실제 서비스 배포를 위한 브랜치

- Release: 개발 진행의 경과가 되는 브랜치로 QA 및 일정관리의 지표가 된다.

- Develop: 각 개발자들이 실시간으로 머지하는 브랜치로 테스트 서버의 소스코드가 보관된다.

- Feature: 각 개발자들이 임의로 자신들의 작업량을 작업한다.

Input validation

본 프로젝트에서는 클라이언트의 요청값을 검증함에 있어 모든 요청의 형태를 DTO 형태로 정의하고 해당 DTO 에 값을 넣기 전에 Joi 라이브러리를 사용하여 요청값에 대한 검증을 수행한다.

tsconfig setting

각 파일에서 다른 파일을 import 함에 있어서 보다 가독성을 높이기 위해 @domain과 같이 태그를 하여 손쉽게 import를 할 수 있습니다.

tsconfig.json 파일의 예

1
2
3
4
5
6
7
8
9
10
11
12
13
{

"compilerOptions": {

"paths": {

"@domain/": ["server/domain/"]

}

}

}

위처럼 옵션을 설정하면 복잡한 filepath 대신 위의 태그네임을 통해 import 할 수 있습니다.

이때 위의 태그네임이 잘 반영이 되지 않는 경우가 있는데, 이는 웹팩에서 트랜스파일링을 하는 과정에서 webpack.config.js 세팅을 바꾸어 줌으로써 해결이 가능합니다.

태그 네이밍을 하기 위해서 tsconfig-paths-webpack-plugin 을 사용하는데 해당 플러그인은 다음과 같이

루트 plugin이 아닌 resolve 내의 plugin 내에 설정되어야 합니다.

webpack.config.js의 예

\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

{

​ resolve: {

​ plugins: [

new TsconfigPathsPlugin({

​ configFile: './tsconfig.json' // setup tsconfig path

​ })

​ ];

​ }

}

\

Author

frontalnh(Namhoon Lee)

Installation

1
2
3
4
5
6
7
8
vue init nuxt-community/typescript-template [프로젝트 명];

yarn add nuxt-property-decorator && # property decorator installation
yarn add tsconfig-paths-webpack-plugin &&# webpack 에서 typescript 를 사용하기 위한 세팅
yarn add ts-loader && # typescript 사용을 위한 ts-loader 설치
yarn add vuex-class && # Vuex 를 class 타입으로 사용하기 위해 설치
yarn add nuxt-sass-resources-loader && # For using sass
yarn add sass-loader # for using sass

타입스크립트를 트랜스파일링 하기 위해 webpack configuration을 바꾸어 주어야 한다.

이는 nuxt.config.js 에서 webpack configuration 을 overriding 함으로써 구현한다.

nuxt.config.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
build: {
/*
** You can extend webpack config here
*/
extend(config, ctx) {
config.resolve.extensions.push('.ts');

const tsLoader = {
loader: 'ts-loader',
options: { appendTsSuffixTo: [/\.vue$/], transpileOnly: true },
exclude: [/vendor/, /\.nuxt/]
};

config.module.rules.push({ test: /.tsx?$/, ...tsLoader });

for (let rule of config.module.rules) {
if (rule.loader === 'vue-loader') {
rule.options.loaders = {
ts: tsLoader
};
}
}

let plugin = new TsconfigPathsPlugin({
configFile: 'tsconfig.json' // setup tsconfig path
});

config.resolve['plugins'] = [plugin];
}
}

Next CLI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# install dependencies

$ npm install # Or yarn install

# serve with hot reload at localhost:3000

$ npm run dev

# build for production and launch server

$ npm run build

$ npm start

# generate static project

$ npm run generate

Vuex

store 디렉토리는 어플리케이션에서 사용하는 도메인 객체들의 저장소이다.

초기 프로젝트는 Vuex 가 disable 된 상태이나 다음과 같이 store/index.js 파일을 작성하면, Vuex 를 사용할 수 있다.

store/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vuex from 'vuex';

const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
mutations: {
increment(state) {
state.counter++;
}
}
});
};

export default createStore;

Vuex state 의 경우 nested 된 object 의 경우 내부 값만 바뀌면 store 가 업데이트 되지 않는 현상이 있다.

이를 위한 해결법으로 state.prop[key] ={} 와 같은 연산이 있다면 이를 state.prop={[key]:{}} 와 같이 수정하는 트릭을 쓸 수 있다.

Global CSS

nuxt.config.js 에서 head 에 추가한다.

Setup Vuetify

1
yarn add @nuxtjs/vuetify
1
2
3
4
import Vuetify from 'vuetify';

Vue.use(Vuetify);
import 'vuetify/dist/vuetify.min.css'; // Ensure you are using css-loader

nuxt.config.js

1
2
3
4
5
6
7
8
9
10
{
modules: [
'@nuxtjs/vuetify'
],

// Vuetify options
vuetify: {
// theme: { }
}
}

Nuxt 에서 axios 사용하기

기본 사용법

Nuxt 에서는 기본적으로 다음과 같은 방법을 통해 axios 모듈을 사용할 수 있다.

여기서, 왜 그냥 axios 를 동적으로 import 해서 사용하지 않고 nuxt 가 제공하는 axios 를 사용해야 하는지 궁금할 수 있다.

바로 그 이유는, nuxt 는 기본적으로 server redering 방식으로 동작하기 때문에, browser cookie 와 jwt 토큰 등의 중앙적인 데이터에 접근하기가 힘들기 때문이다.

nuxt 가 제공하는 axios 는 withCredential 등을 통해 간편하게 cookie 데이터에 접근할 수 있는 장점이 있다.

axios 설치

1
npm install @nuxtjs/axios

axios 모듈 등록

nuxt.config.ts

1
2
3
4
5
6
7
8
module.exports = {
modules: [
'@nuxtjs/axios',
],
axios: {
// proxyHeaders: false
}
}

이를 통해 각 component 의 this.$axioscontext 의 $axios 를 통해 axios를 사용할 수 있다.

하지만, 여기서는 범용 logger 혹은 http request 에 있어서 일관된 에러 핸들링 등을 할 수 없기 때문에 이 함수를 사용하는 httpHelper 플러그인을 구현하여 이를 가능하도록 한다.

http helper plugin 적용

여기서 httpHelper의 경우 get, post, put, delete 등의 메소드를 wrapping 하는 다양한 함수들이 존재하며 여기서는 구현을 생략하겠다.

중요한 점은 이런 HttpHelper 클래스가 plugin 에서 $axios 를 주입받아 새로운 메소드를 구현하며, 이를 inject 함수를 통해 vue instance, store, context 에 바인딩 하여 어느 곳에서나 사용 가능하게 해준다는 것이다.

plugins/httpHelper.ts

1
2
3
4
5
6
7
8
9
import { HttpHelper } from 'utils/httpHelper';

export default function(context, inject) {
let { $axios } = context;
let httpHelper = new HttpHelper($axios);
context.$httpHelper = httpHelper;

inject('httpHelper', httpHelper);
}

Plugin 사용하기

Vue.js 의 자체 기능 뿐 아니라 다양한 외부 라이브러리 혹은 사용자의 external util function 등을 활용하기 위해서 nuxt 는 plugin 이라는 기능을 제공한다.

이러한 plugin 을 통해서 사용자는 사용하고자 하는 함수 혹은 instance 를 vue root application 혹은 context 에 binding 할 수 있다.

플러그인 만들기

plugins/sample.ts

1
2
3
4
5
export default (context, inject) => {
context.$sample = a => {
console.log(a);
};
};

플러그인 등록하기

플러그인을 사용하기 위해 nuxt configuration 에 등록시켜 주어야 한다.
nuxt.config.ts

1
2
3
export default {
plugins: ['~/plugins/sample.ts']
};

Vue instance, Contextk, Store 에서 사용가능하게 등록하기

기본적으로 plugin 을 등록하면 오직 context 혹은 vue instance 내에서만 사용 가능하다.
하지만 store 혹은 여러 곳에서 이 함수 혹은 인스턴스에 접근하고자 한다면 inject 함수를 이용하여 전역에서 사용가능하게 등록시켜 주어야 한다.

아래처럼 'sample' 과 같이 $ 기호를 생략하고 등록해 주면 $sample 과 같이 변형되어 바인딩 된다.

1
2
3
4
5
6
7
8
9
10
11
12
export default (context, inject) => {
let sample = a => {
console.log(a);
};
let sample2 = {
b: x => {
console.log(x);
}
};
inject('sample', sample);
inject('sample2', sample2);
};

이를 통해 context, Vue 인스턴스 내에서의 this 등 어디에서는 이곳에 접근할 수 있게 된다.

Reverse proxy

클라이언트가 서버를 호출하는 경우 cors(cross origin resource sharing 문제로 브라우저 내에 렌더링 된 페이지를 준 호스트가 아닌 다른 곳으로의 요청은 기본적으로 막혀있다.

사실 이는 nuxt.js 뿐만이 아니라 대부분의 웹 어플리케이션 배포 과정에서 나타나는 문제인데, nuxt.js 에서는 그 해결과정이 조금 다르기 때문에 작성한다.

다른 어플리케이션 배포과정의 경우 일반적으로 nginx 와 같은 web server 를 사용하여 reverse proxy 를 통해 클라이언트 내의 서버 요청 url 을 같은 호스트로 설정하고, 같은 호스트로 오는 요청의 url 을 분석하여 같은 호스트 내의 다른 포트로 리다이렉팅 시켜주는 등의 해결법을 제시하지만, nuxt.js 의 경우 server rendering 프레임워크로 독자적으로 hosing 을 하는 만큼, 자체적으로 reverse proxy 를 제공하며, nuxt.config.js 파일에 다음과 같이 reverse proxy 설정을 주어 해결할 수 있다.

nuxt.config.js

1
2
3
4
5
6
7
const serverUrl = "localhost:3002";

module.exports = {
proxy: {
'/api/': serverUrl
},
}

Global Modal

전역으로 alert와 dialog를 사용하기 위해 layout 레이어에서 해당 모듈을 구현하였으며, 이는 page store 를 통해 접근이 가능하다.

Environment variables

node.js 서버와는 달리 nuxt 의 경우는 동작환경이 브라우저 이므로, 서버에서 하듯이 process.env 와 같이 환경변수에 접근해도 브라우저의 환경변수이기 때문에 접근이 되지 않는다. 이는 매우 기본적인 사실이지만 서버렌더링을 하는 과정에서 혼동될 수 있다.

즉, nuxt.js 에서 process.env 를 사용한다면, 이는 빌드시점에 주입되어야 할 것이다.

Problem solving

layout 사용하기

vue component class 를 사용함에 있어 layout 옵션이 설정되지 않았다면 다음 코드를 index.d.ts 에 추가한다.

1
2
3
4
5
6
7
8
9
declare module 'vue/types/options' {

interface ComponentOptions<V extends Vue> {

layout?: string;

}

}

Unexpected token import

모든 기능이 정산인데 갑자기 Unexpected token import 에러가 났다.

이 경우 최종 문제의 원인은

nuxt.config.js에서 modules 에 bootstrap-vue 를 import 함에 있어 bootstrap-vue/nuxt 가 아니라 @nuxtjs/bootstrap-vue 를 import 하여 생기는 문제였다.

bootstrap-vue 공식 홈페이지에도 bootstrap-vue/nuxt 를 import 하라고 하고 있는데, 이를 매우 주의하여야 한다.

cannot find module

nuxt property decorator 를 사용할때

1
{components:{}} 속성을 추가하지 않으면 모듈을 찾지 못하는 문제가 생긴다.

Query string nested object

기존에는 querystring 라이브러리를 사용하여 nested object 를 처리하지 못하였으나, qs 라이브러리를 사용하면 해결 가능하다.

Custom Component 의 click 이벤트를 자식 요소로 넘기는 법

1
@click.native

다른 vuex 모듈에서 다른 vuex 모듈에 있는 액션을 호출하는 법

Javascript Cookbook

Object

assign()

assign 함수는 특정 객체의 값을 복사하는 함수입니다. assign 함수를 통해 두 개 이상의 객체를 병합하는 등의 작업을 수행 가능합니다.

assign 함수는 아래와 같이 사용되며 대상 객체를 반환합니다.

example

1
Object.assign(target, ...source)

객체 복사하기

1
2
var source = { a: 1 };
var target = Object.assign({}, source);

위와 같이 Object.assign은 객체를 복사하는 데 사용될 수 있으며, {} 처럼 빈 객체를 넣고 반환값을 받음으로써 빈 객체에 source 가 되는 object를 복사할 수 있습니다.

객체 병합하기

assign 함수를 통해 객체를 병합 할 수 있습니다. 가령 a, b 객체가 있고 각각의 키값을 하나로 병합하고 싶다면 다음과 같이 수행 할 수 있습니다.

1
2
3
4
var obj1 = { a:1, b:2 };
var obj2 = { a:1, c:4, d:5 };

var target = Object.assign({}, obj1, obj2);

이처럼 만약 동일한 key를 가졌다면 뒤에 오는 source의 key, value 들로 덮어씌워지는 방식으로 복사될 것입니다.

keys()

entries()

entries 함수는 object의 키들을 열거가능한 [key, value] 쌍을 리턴해 주며, 다음과 같이 사용됩니다.

example

1
2
3
var obj = { a:1, b:2, c:3 };
var entries = Object.entries(obj);
// [["a", 1],["b", 2],["c", 3]]

객체 내의 다양한 키들을 순환하는 로직을 구현 하는 경우 이는 매우 효과적이며 다음과 같이 사용됩니다.

exmaple

1
2
3
4
5
6
var obj = { a:1, b:2, c:3 };
var entries = Object.entries(obj);
entries.foreach((key, value)=>{
// do some stuff
console.log(key, value);
})

Map

js에서 Map 이란 일종의 key 와 value의 쌍으로 흔히 object와 비슷한 역할을 수행하지만, object와 달리 어떤 종류의 값도 저장할 수 있는 장점이 있으며, 흔히 대량의 자료가 저장되는 경우 object에 비해 훨씬 좋은 성능을 보인다.

이번 포스트에서는 Map 이 가진 다양한 함수들과 이에 대한 활용법에 대해 알아보도록 한다.

example

1
new Map([iterable]) //key, value pair

set

1
2
var map = new Map([[a, 1], [b, 2]]);
map.set(c, 3);

get

1
2
var map = new Map([[a, 1], [b, 2]]);
map.get(1);

delete(key)

1
2
var exampleMap = new Map([a, 1], [b, 2]);
exampleMap.delete(a);

foreach

1
2
3
4
var example = new Map([a, 1], [b, 2]);
example.foreach((value, key){
// do some stuff here.
})

Array

sort()

array의 sort는 배열을 정렬하기 위한 아주 좋은 method 입니다.

sort는 뒤에 오는 콜백함수를 계속 실행하여 callback(a, b)의 값이 0보다 작은 경우 a를 앞으로 보내고, 0보다 큰 경우 a를 뒤로 보내는 방식으로 동작합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 정상 동작 */
score.sort(function(a, b) { // 오름차순
return a - b;
// 1, 2, 3, 4, 10, 11
});

score.sort(function(a, b) { // 내림차순
return b - a;
// 11, 10, 4, 3, 2, 1
});

student.sort(function(a, b) { // 오름차순
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
// 광희, 명수, 재석, 형돈
});

student.sort(function(a, b) { // 내림차순
return a.name > b.name ? -1 : a.name < b.name ? 1 : 0;
// 형돈, 재석, 명수, 광희
});

splice()

array.splice(i,1)를 통해 index i 로 부터 1개의 요소를 제거하고 제거한 자리에 값을 추가한다.

example

1
2
3
4
var array = [0, 1, 2, 3, 4, 5];
array.splice(2, 1);
//array에는 세번째 요소가 빠진 상태가 된다.
[0, 1, 3, 4, 5]

delete

특정 요소를 삭제할 때 사용한다.

1
2
var arr = ["a", "b", "c"];
delete arr[1];

pop

array를 stack으로 사용하는 경우 pop() 함수는 매우 유용하며, 가장 우측의 element를 제거한다.

example

1
2
3
4
5
6
7
let list = [1, 2, 3, 4, 5, 6, 7];

console.log('original list: ', list);

let poped = list.pop();
console.log('poped item: ', poped);
console.log('list after pop() executed: ', list);

Push

리스트에 특정 아이템을 추가하고 추가된 이후에 총 아이템의 갯수를 반환한다.

이 함수는 원래의 리스트를 변형한다.

1
2
3
4
5
console.log('original list: ', list);

let count = list.push('pushed item');
console.log('Total item count after push() executed: ', count);
console.log('list after push() executed: ', list);

shift

shift는 주로 que의 구현에 많이 사용되며, 제일 앞의 element를 제거하고 반환해 준다.

1
2
3
4
5
console.log('original list: ', list);

let shifted = list.shift();
console.log('shifted item: ', shifted);
console.log('list after shift() executed: ', list);

unshift()

제일 앞쪽에 밀어 넣는다.

example

1
2
var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.unshift("Lemon"); // Adds a new element "Lemon" to fruits

foreach(()=>{})

모든 어레이값에 대해 연산을 수행하는 함수이며 다음과 같이 사용된다.

1
2
3
4
var arr = [1, 2, 3, 4, 5];
arr.foreach((element, index, array)=>{
console.log(element);
})

reduce

reduce는 array의 모든 값에 대해 계속해서 callback함수를 실행시키는 함수이며 다음과 같은 용도로 사용합니다.

syntax

1
2
3
4
var arr = [1, 2, 3, 4, 5];
arr.reduce((accumulator, currentValue, currentIndex, array)=>{
// do some stuff here.
})

여기서 첫번째 인자인 accumulator는 계속해서 다음 callback의 인자로 전달되는 값이며 어떤 변환을 하더라도 해당 변환 내용이 다음으로 전달되며, currentValue는 현재 값을 나타냅니다.

배열에서 가장 큰 값을 구하기

accumulator를 통해 계속 앞의 return 값을 받아와 비교하면서 가장 큰 값을 구할 수 있습니다.

1
2
3
4
var arr = [1, 2, 3, 4, 5];
var max = arr.reduce((before, current)=>
return before<current ? current : before
)
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×