<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>cod_kms.log</title>
        <link>https://velog.io/</link>
        <description>3년차 백엔드 개발자</description>
        <lastBuildDate>Wed, 05 Feb 2025 02:59:56 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. cod_kms.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cod_kms" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[chapter1. Refactoring: A First Example]]></title>
            <link>https://velog.io/@cod_kms/chapter1.-Refactoring-A-First-Example</link>
            <guid>https://velog.io/@cod_kms/chapter1.-Refactoring-A-First-Example</guid>
            <pubDate>Wed, 05 Feb 2025 02:59:56 GMT</pubDate>
            <description><![CDATA[<ul>
<li>The Starting Point</li>
<li>Comments on the Starting Program</li>
<li>The First Step in Refactoring</li>
<li>Decomposing the statement Function</li>
</ul>
<blockquote>
<p><a href="https://mire-salt-f24.notion.site/1-241220-Chapter1-Refactoring-A-First-Example-16f27fdb9a6180578e2bc056c042ee83?pvs=4">https://mire-salt-f24.notion.site/1-241220-Chapter1-Refactoring-A-First-Example-16f27fdb9a6180578e2bc056c042ee83?pvs=4</a></p>
</blockquote>
<br>

<ul>
<li>Status: Lots of Nested Functions</li>
<li>Splitting the Phases of Calculation and Fomatting</li>
<li>Status: Seperated into Two Files (and Phases)</li>
<li>Reorganizing the Calculations by Type</li>
<li>Status: Creating the Data with the Polymorphic Calculator</li>
<li>Final Thoughts<blockquote>
<p><a href="https://mire-salt-f24.notion.site/2-241227-Chapter1-Refactoring-A-First-Example-16f27fdb9a618052a687da8b3499a2bc?pvs=4">https://mire-salt-f24.notion.site/2-241227-Chapter1-Refactoring-A-First-Example-16f27fdb9a618052a687da8b3499a2bc?pvs=4</a></p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[chapter0. Preface]]></title>
            <link>https://velog.io/@cod_kms/chapter0.-preface</link>
            <guid>https://velog.io/@cod_kms/chapter0.-preface</guid>
            <pubDate>Wed, 05 Feb 2025 02:52:20 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://mire-salt-f24.notion.site/Preface-15a27fdb9a61806bab15c70a46180be8?pvs=4">https://mire-salt-f24.notion.site/Preface-15a27fdb9a61806bab15c70a46180be8?pvs=4</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] DTO]]></title>
            <link>https://velog.io/@cod_kms/NestJS-DTO</link>
            <guid>https://velog.io/@cod_kms/NestJS-DTO</guid>
            <pubDate>Thu, 09 Jan 2025 06:47:07 GMT</pubDate>
            <description><![CDATA[<h2 id="dto-data-trasnfer-object">DTO (Data Trasnfer Object)</h2>
<blockquote>
<p>데이터 전송 객체로, 계층 간 데이터를 교환하기 위해 사용하는 객체</p>
</blockquote>
<p>주로 Database에서 가져온 데이터를 Service 또는 Controller 계층으로 전달하거나,
반대로 클라이언트로부터 받은 데이터를 처리하기 위해 사용된다.</p>
<p>쉽게 말해서 데이터를 주고받을 객체의 타입을 체크해주기 위한 구조라고 하면 될 것이다.</p>
<p>NestJS와 같은 프레임워크에서 데이터를 처리할 때 필수적인 역할을 한다.
데이터 구조를 명확히 정의하고, 유지보수성과 안정성을 높이는 데 유용하다.</p>
<p>DTO에는 Validator라는 것을 붙일 수 있어서 데이터에 대한 검증까지 진행할 수 있다.</p>
<p>추가적으로, Nest.js의 경우 DTO에 Swagger 관련 작업을 할 수 있어서 자동적으로 Swagger가 만들어지도록 하는 것도 가능하다.</p>
<p>DTO는 class와 interface 두 가지를 사용하여 정의할 수 있다. 무슨 차이일까 ?</p>
<br>

<h2 id="interface--class">Interface &amp; class</h2>
<h3 id="interface">Interface</h3>
<p>데이터의 구조와 타입만 정의하는 데 사용된다.</p>
<p>컴파일 시점에만 존재하기 때문에 TypeScript가 JavaScript로 변환되면 interface는 사라지고, 
런타임에서는 어떤 형태로도 작동하지 않는다.</p>
<p>다중 상속이 가능하여 여러 interface를 조합하여 새로운 구조를 정의할 수 있다.</p>
<h3 id="class">class</h3>
<p>데이터의 구조뿐만 아니라 메서드와 기능도 포함할 수 있는 객체를 정의한다.</p>
<p>런타임에서도 존재하기 때문에 Javascript로 변환되어 런타임에서도 사용이 가능하다.
<code>@nestjs/common</code>의 데코레이터(<code>@Body, @Param</code> 등)와 함께 사용할 수 있음.</p>
<p>데이터를 초기화하거나 기본값을 설정할 수 있으며 다른 클래스를 확장해서 사용 가능하다.</p>
<h3 id="nestjs-에서는--span-stylecolor-orangeinterface-vs-classspan">NestJs 에서는 ? <span style="color: orange">Interface vs. class</span></h3>
<p>공식문서에서는 <strong>Class</strong>를 이용해서 <strong>DTO를 구성하는 것을 추천</strong>하고 있다.</p>
<p>Class는 런타임에서도 존재하므로, 
NestJS 데코레이터 및 유효성 검증 라이브러리(class-validator)와 함께 사용이 가능하다.
반면, Interface는 컴파일 시 제거되어 DTO 정의용으로 부적합하다는 것이다.</p>
<p>하지만 단순하게 데이터 구조만 정의하고 추가 로직이 필요 없을 시 interface를 사용해도 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] 특정 프로젝트에서 깃허브 계정 다르게 설정하는 법]]></title>
            <link>https://velog.io/@cod_kms/%ED%8A%B9%EC%A0%95-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C-%EA%B9%83%ED%97%88%EB%B8%8C-%EA%B3%84%EC%A0%95-%EB%8B%A4%EB%A5%B4%EA%B2%8C-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B2%95</link>
            <guid>https://velog.io/@cod_kms/%ED%8A%B9%EC%A0%95-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90%EC%84%9C-%EA%B9%83%ED%97%88%EB%B8%8C-%EA%B3%84%EC%A0%95-%EB%8B%A4%EB%A5%B4%EA%B2%8C-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B2%95</guid>
            <pubDate>Thu, 09 Jan 2025 05:11:59 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>회사에서 진행하고 있는 A 프로젝트는 깃허브 회사 개인 계정에 연결되어있다.
개인 프로젝트를 진행하기 위해 B 프로젝트를 새롭게 만들어 개인 계정에 연결하고 싶었다.
개인 계정에 repo를 만든 뒤 remote 연결을 했는데 push 하니 에러가 발생했다.</p>
<pre><code class="language-bash">user@user-MacBookPro project-name % git push origin main
remote: Permission to b-git-username/repo-name.git denied to a-git-username.
fatal: unable to access &#39;https://github.com/b-git-username/repo-name.git/&#39;: The requested URL returned error: 403</code></pre>
<br>

<h2 id="해결-단계">해결 단계</h2>
<h3 id="1-현재-git-저장소에-등록되어-있는-이메일과-계정-이름-확인">1. 현재 git 저장소에 등록되어 있는 이메일과 계정 이름 확인</h3>
<pre><code class="language-bash">$ git config --list</code></pre>
<pre><code class="language-bash">user@user-MacBookPro project-name % git config --list
credential.helper=osxkeychain
user.name=b-git-username
user.email=b-git-username@gmail.com
credential.helper=osxkeychain
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=tru</code></pre>
<p>결과에서 global로 설정된 <span style="color:olivedrab"><strong>계정 정보</strong></span>인
<code>user.name=b-git-username</code>, <code>user.email=b-git-username@gmail.com</code>를 볼 수 있다.</p>
<p>git 저장소에 저장되어 있는 <code>global</code>보다 높은 우선 순위를 가진 것이 바로 <code>local</code> 이다.
즉, 프로젝트를 하나 생성하고 따로 다른 계정으로 관리하고자 한다면 <code>local config</code> 설정을 해주어야 한다.</p>
<p>그렇지 않으면 <code>local</code> 설정이 없기 때문에
프로젝트를 새로 생성한다하더라도 <code>commit, push</code>를 하게 되면 무조건 <code>global</code>의 설정을 따르게 된다.</p>
<br>

<h3 id="2-따로-관리하고자-하는-프로젝트-경로로-진입-후-local-계정을-등록한다">2. 따로 관리하고자 하는 프로젝트 경로로 진입 후 local 계정을 등록한다.</h3>
<pre><code class="language-bash">$ git config --local user.name &#39;git 계정이름&#39;
$ git config --local user.email &#39;git 등록 이메일&#39;</code></pre>
<pre><code class="language-bash">credential.helper=osxkeychain
user.name=kristin-min
user.email=kms@kristinkorea.com
credential.helper=osxkeychain
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
core.precomposeunicode=true
user.name=backend-kms
user.email=mindu6424@naver.com</code></pre>
<p>그 후 다시 <code>git config --list</code> 명령어로 확인해보면 위와 같이 맨 아래 부분에</p>
<pre><code class="language-bash">user.name=backend-kms
user.email=mindu6424@naver.com</code></pre>
<p>가 추가된 것을 확인할 수 있다. 이것이 local로 설정한 계정 정보이다.</p>
<br>

<h3 id="3-ssh-key-등록">3. ssh-key 등록</h3>
<h4 id="1-ssh-숨김-폴더로-이동-후-목록-확인"><strong>1.</strong> .ssh 숨김 폴더로 이동 후 목록 확인</h4>
<pre><code class="language-bash">$ cd ~/.ssh
$ ls</code></pre>
<br>

<h4 id="2-ssh-key-생성"><strong>2.</strong> ssh-key 생성</h4>
<pre><code>$ ssh-keygen -t [암호화 방식] -b [생성할 key의 크기] -C &#39;등록할 GitHub 주소&#39;</code></pre><p><code>-t</code>: 암호화 방식을 지정하며 <strong>[암호화 방식]</strong>은 보통 <code>rsa</code>를 사용한다. 현재까지 안전하게 사용 가능한 방식이다. 하지만 최신 환경에서는 <code>ed25519</code>도 권장되는 방식이다.</p>
<p><code>-b</code>: 생성할 <code>key</code>의 크기이며, <strong>[생성할 key의 크기]</strong>는 보통 3072비트 혹은 4096비트로 설정한다. 크기가 클수록 보안은 높지만 성능에 영향을 줄 수 있다. 보통 3072비트로도 충분한 보안을 제공한다.</p>
<p><code>-C</code>: 등록할 깃허브의 메일 주소를 의미하며, SSH 키에 식별자를 추가하는 것이다.</p>
<br>

<pre><code class="language-bash">ex) ssh-keygen -t rsa -b 3072 -C &quot;your_email@example.com&quot;</code></pre>
<p>정상적으로 실행된다면</p>
<br>

<p><code>Generating public/private rsa key pair.</code> 라는 메세지가 나온다.</p>
<p><code>Enter file in which to save the key (/Users/whkwon/.ssh/id_rsa):</code>에서 그냥 Enter을 치게 되면 id_rsa 라는 기본 이름의 파일로 저장이 되며, 원하는 명칭이 있다면 적으면 된다.</p>
<p><code>Enter passphrase (empty for no passphrase):</code> 이름을 설정하면 이렇게 비밀번호를 입력한다.</p>
<p><code>Enter same passphrase again:</code> 한번 더 입력한다.</p>
<br>

<p>이제 여기서</p>
<pre><code>Your identification has been saved in /Users/username/.ssh/id_rsa
Your public key has been saved in /Users/username/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:0MjCsjfhsdkjfhsdjkfhsjdkfhdkshfSHz0JgyrU ‘your_email@example.com’
The key&#39;s randomart image is:
+---[RSA 4096]----+
|       .+*.O=    |
|         ...M=.  |
|        .. ==+ . |
|       . .... .  |
|      ,,,        |
|   o o + o .     |
|  .........      |
|   o...... .     |
|       ......... |
+----[SHA256]-----+</code></pre><p>가 나오게 되면 정상적으로 ssh-key가 생성된 것이다.</p>
<br>

<h4 id="3-ssh-key-등록-1"><strong>3.</strong> ssh-key 등록</h4>
<p>이제 <code>ssh-key</code>를 등록해야한다. <code>ssh-key</code>는 pub가 붙지 않은 비밀키를 등록한다.</p>
<pre><code class="language-bash">$ ssh-add [생성된 ssh-key의 경로]</code></pre>
<p>명령어를 실행하면</p>
<p><code>Identity added: /Users/username/.ssh/id_rsa_name (your_email@gmail.com)</code></p>
<p>라는 쉘이 나오면 된다.</p>
<br>

<h4 id="4-vi를-통한-ssh-config-파일-작성"><strong>4.</strong> vi를 통한 ssh config 파일 작성</h4>
<p><code>/.ssh</code> 경로에 <code>config</code> 파일을 생성한 후 다음 내용을 작성한다.</p>
<pre><code class="language-bash">$ vi ~/.ssh/config</code></pre>
<pre><code>Host github.com-**wantname**
                  # 원하는 이름 지정
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
               # ssh-key 파일 경로
  User github_name
       # GitHub 계정 이름</code></pre><br>

<h4 id="5-github에-ssh-key-등록-후-설정-최종-확인"><strong>5.</strong> github에 ssh-key 등록 후 설정 최종 확인</h4>
<blockquote>
<p>Github -&gt; 우측 상단 프로필 -&gt; Settings -&gt; SSH and GPG keys -&gt; New SSH Key 후 생성</p>
</blockquote>
<p><strong>pub 키의 내용 확인법</strong></p>
<pre><code class="language-bash">cat ~/.ssh/id_rsa.pub</code></pre>
<br>

<p>제대로 되었는지 확인하기 위해</p>
<pre><code class="language-bash">$ ssh -T git@github.com-Host옆에지은ID(필자: wantname)</code></pre>
<pre><code>Hi wantname! You&#39;ve successfully authenticated, but GitHub does not provide shell access.
</code></pre><br>

<h2 id="야기될-수-있는-문제점-2가지">야기될 수 있는 문제점 2가지</h2>
<h3 id="1-ip-주소-변경으로-인한-의심">1. IP 주소 변경으로 인한 의심</h3>
<p>SSH 연결 시, <code>“The authenticity of host &#39;github.com (00.000.00.000)&#39; can&#39;t be established.”</code>는 메시지가 나타난 것으로 보인다.
메시지가 뜨면 현재 IP 주소를 신뢰하는 경우 yes를 입력하면 정상적으로 진행된다.</p>
<h3 id="2-컴퓨터-재시작-후-ssh-키가-사라짐">2. 컴퓨터 재시작 후 SSH 키가 사라짐</h3>
<p>컴퓨터를 재시작하면 SSH 에이전트에 추가했던 SSH 키 정보가 초기화된다.
이로 인해 git push 또는 git pull 시 문제가 발생한다.
-&gt; SSH 키를 에이전트에 다시 추가해야 한다.</p>
<pre><code class="language-bash">$ ssh-add ~/.ssh/id_rsa_name7777</code></pre>
<p>하지만 매번 반복적인 일을 수행해야 하므로 번거롭다.
그래서 SSH 키를 자동으로 추가하도록 설정하는 것을 추천한다.</p>
<p>SSH 설정 파일<code>(~/.ssh/config)</code>을 열어 아래 내용을 추가한다.</p>
<pre><code class="language-plain">AddKeysToAgent yes</code></pre>
<p>이 설정은 모든 SSH 연결에서 해당 키를 자동으로 사용하도록 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] Module]]></title>
            <link>https://velog.io/@cod_kms/NestJS-Module</link>
            <guid>https://velog.io/@cod_kms/NestJS-Module</guid>
            <pubDate>Thu, 09 Jan 2025 00:17:23 GMT</pubDate>
            <description><![CDATA[<h2 id="module의-기본적인-구조">Module의 기본적인 구조</h2>
<pre><code>AppModule (root)
├ AModule
│   ├ Entity
│   ├ Controller
│   ├ Service
│   ├ Repository
│   └ ValidationPipe | JWT, Passport | ...
├ BModule
└─CModule</code></pre><br>

<h2 id="nestjs-module">NestJS Module</h2>
<blockquote>
<p>@Module() 데코레이터로 주석이 달린 클래스로, @Module() 데코레이터는 Nest가 애플레이션 구조를 구성하는 데 사용하는 메타데이터를 제공한다.</p>
</blockquote>
<br>

<h3 id="루트모듈">루트모듈</h3>
<p><strong>모든 NestJS 애플리케이션에는 반드시 하나의 루트 모듈이 있어야 한다.</strong>
<strong>루트 모듈은 Nest가 사용하는 시작점이다.</strong></p>
<h3 id="기능별-모듈화">기능별 모듈화</h3>
<p>모듈은 밀접하게 관련된 기능들을 하나로 묶는 데 사용된다.
같은 기능에 속하는 구성 요소(컨트롤러, 서비스, 프로바이더 등)를 한 모듈 안에 배치하여 관리한다.</p>
<h3 id="싱글톤singleton-설계">싱글톤(Singleton) 설계</h3>
<p>모듈은 기본적으로 싱글톤으로 동작한다.
따라서 여러 모듈 간에 동일한 프로바이더 인스턴스를 공유할 수 있다.</p>
<h3 id="구조화된-관리">구조화된 관리</h3>
<p>기능별로 모듈을 나누면 프로젝트가 커져도 유지보수와 확장이 쉽다.</p>
<h3 id="요약">요약</h3>
<blockquote>
<p><strong>NestJS 모듈은 관련된 기능 집합을 체계적으로 관리하며, 
재사용성과 유지보수성을 극대화하기 위한 핵심적인 설계 도구이다.</strong></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] 개념 정리 및 설치 방법]]></title>
            <link>https://velog.io/@cod_kms/NestJS-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@cod_kms/NestJS-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 08 Jan 2025 04:45:08 GMT</pubDate>
            <description><![CDATA[<h2 id="nestjs">NestJS</h2>
<blockquote>
<p> 효율적이고 확장 가능한 Node.js 서버 사이드 애플리케이션을 구축하기 위한 프레임워크이다.
Node.js에 기반을 둔 웹 API 프레임워크로써 Express 또는 Fastify 프레임워크를 래핑하여 동작한다.</p>
</blockquote>
<br>

<h2 id="document">Document</h2>
<p><a href="https://docs.nestjs.com/">https://docs.nestjs.com/</a></p>
<br>

<h2 id="nestjs-설치-방법">NestJS 설치 방법</h2>
<ol>
<li><p>Node.js 설치 - 설치 방법은 Node.js 설치 방법 페이지 참조
<a href="https://velog.io/@cod_kms/Node.js-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-MacOS">https://velog.io/@cod_kms/Node.js-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-MacOS</a></p>
</li>
<li><p>NestJS CLI 설치</p>
</li>
</ol>
<p><strong>NestCLI란</strong> Nest Application의 초기화, 개발 및 유지 관리를 도와주는 인터페이스 도구</p>
<pre><code class="language-bash">npm i -g @nestjs/cli</code></pre>
<pre><code>i: install 명령어의 약자
-g: 컴퓨터의 글로벌 환경에 설치하겠다는 뜻으로, 모든 디렉토리에서 참조할 수 있음

npm root -g: 글로벌 환경에서 패키지가 설치되는 경로 확인 명령어

* npm 에러 발생시 관리자 권한으로 설치: sudo npm i -g @nestjs/cli</code></pre><ol start="3">
<li>프로젝트 생성 방법<pre><code class="language-bash">mkdir 폴더명</code></pre>
<pre><code class="language-bash">cd 폴더명</code></pre>
<pre><code class="language-bash">nest new project-name</code></pre>
</li>
</ol>
<br>

<h2 id="보일러플레이트-nest-new-project-name-설명">보일러플레이트 nest new project-name 설명</h2>
<h3 id="src-폴더">src 폴더</h3>
<pre><code>-&gt; app.controller.spec.ts
   컨트롤러에 대한 단위테스트

-&gt; app.controller.ts
   유저와 통신하고 서비스의 패턴을 정의하는 컨트롤러

-&gt; app.module.ts
   Application의 실행 루트 모듈

-&gt; app.service.ts
  실제 로직을 구현하는 기본 서비스

-&gt; main.ts
   NestJS Application 인스턴스를 생성하는 메인</code></pre><h3 id="eslintrcjs">.eslintrc.js</h3>
<p>개발자들이 특정한 규칙을 가지고 코드를 깔끔하게 짤 수 있도록 도와주는 라이브러리
타입 스크립트를 쓰는 가이드라인 제시
문법에 오류가 나면 알려주는 역할</p>
<h3 id="gitignore">.gitignore</h3>
<p>Git에서 특정 파일이나 디렉토리를 버전 관리 대상에서 제외할 때 사용하는 파일
이 파일에 정의된 패턴에 해당하는 파일이나 폴더는 Git이 추적하지 않으며, 커밋 대상에서 제외됨</p>
<h3 id="prettierrc">.prettierrc</h3>
<p>주로 코드 형식을 맞추는데 사용하며 에러 찾는 것이 아닌 코드 포멧터 역할을 함
작은 따옴표(’)를 사용할지 큰 따옴표(”)를 사용할지, Indent 값을 2로 줄지 4로 줄지 등등</p>
<h3 id="nest-clijson">.nest-cli.json</h3>
<p>nest 프로젝트를 위해 특정한 설정을 할 수 있는 json 파일</p>
<h3 id="packagejson">.package.json</h3>
<p>프로젝트 이름, 버전, 설명, 작성한 사람 명시
bulid: 운영 환경을 위한 빌드
format: 린트 에러가 났을시 수정
start: 앱 시작</p>
<h3 id="tsconfigjson">.tsconfig.json</h3>
<p>어떻게 타입스크립트를 컴파일 할 지 설정하는 json 파일</p>
<h3 id="tsconfigbuildjson">.tsconfig.build.json</h3>
<p>tsconfig.json의 연장선상 파일
build할 때 필요한 설정들 excludes에서는 빌드할 때 필요없는 파일들 명시</p>
<br>

<h2 id="애플리케이션-실행-명령어">애플리케이션 실행 명령어</h2>
<pre><code class="language-bash">npm run start:dev</code></pre>
<br>

<h2 id="controller-vs-resolver">Controller vs. Resolver</h2>
<h3 id="controller">Controller</h3>
<ul>
<li>프로토콜: HTTP (RESTful API)</li>
<li>데코레이터: @Controller(), @Get(), @Post() 등</li>
<li>처리 대상: URL 경로 및 HTTP 메서드</li>
<li>응답 대상: JSON, HTML 등</li>
<li>라우팅 방식: 명시적 라우팅 (e.g., /users/:id)</li>
</ul>
<h3 id="resolver">Resolver</h3>
<ul>
<li>프로토콜: GraphQL</li>
<li>데코레이터: @Resolver(), @Query(), @Mutation() 등</li>
<li>처리 대상: GraphQL 타입과 작업(Query/Mutation 등)</li>
<li>응답 대상: GraphQL 스키마에 따른 응답 형식</li>
<li>라우팅 방식: GraphQL 스키마 기반의 요청 매핑</li>
</ul>
<h3 id="선택-기준">선택 기준</h3>
<p>RESTful API를 설계중이라면 Controller 사용</p>
<ul>
<li>HTTP 기반의 요청/응답 패턴과 RESTful 엔드포인트가 필요할 때 적합</li>
</ul>
<p>GraphQL API를 설계중이라면 Resolver 사용</p>
<ul>
<li>GraphQL 스키마를 기반으로 동적이고 유연한 데이터 쿼리 및 변형이 필요할 때 적합</li>
</ul>
<h3 id="nestjs의-graphql-사용">NestJS의 GraphQL 사용</h3>
<p>NestJS에서 기본적으로 Controller를 사용해 RESTful API를 구현한다.
<strong>GraphQL Resolver를 사용하려면 추가 설정</strong>이 필요하다.</p>
<pre><code class="language-bash">npm install @nestjs/graphql apollo-server-express graphql</code></pre>
<pre><code class="language-javascript">// module.ts
import { Module } from &#39;@nestjs/common&#39;;

@Module({
  imports: [
  ],
  providers: [
  ],
  exports: [
  ],
})
export class UserModule { }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Node.js] Node.js 프로그램 설치 방법 (MacOS)]]></title>
            <link>https://velog.io/@cod_kms/Node.js-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-MacOS</link>
            <guid>https://velog.io/@cod_kms/Node.js-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-MacOS</guid>
            <pubDate>Wed, 08 Jan 2025 00:53:10 GMT</pubDate>
            <description><![CDATA[<h3 id="nodejs">Node.js</h3>
<blockquote>
<p><strong>자바 스크립트(JavaScript)</strong>를 실행시켜주는 프로그램</p>
</blockquote>
<h3 id="설치-방법">설치 방법</h3>
<ul>
<li>node.js 사이트 접속 후 LTS 설치</li>
<li>최신 버전은 가급적이면 설치 지양<ul>
<li>버그가 포함되어 있거나, 안정적이지 않을 수도 있음<img src="https://velog.velcdn.com/images/cod_kms/post/ac524ce7-b0c7-4b7d-8049-9a377a8c3dbf/image.png" width="90%" height="%">
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQLAlchemy] SQLAlchemy 로딩 전략]]></title>
            <link>https://velog.io/@cod_kms/SQLAlchemy-%EB%A1%9C%EB%94%A9-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@cod_kms/SQLAlchemy-%EB%A1%9C%EB%94%A9-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Tue, 07 Jan 2025 06:51:32 GMT</pubDate>
            <description><![CDATA[<p><code>joinedload</code>: 관계된 객체를 즉시 로드하기 위해 sql join을 사용</p>
<pre><code class="language-python"># 부모 객체와 자식 객체를 함께 즉시 로드해야할 때 사용
from sqlalchemy.orm import joinedload
query = session.query(Parent).options(joinedload(Parent.children))</code></pre>
<br>

<p><code>subqueryload</code>: 관계된 객체를 서브쿼리로 로드</p>
<pre><code class="language-python"># 부모 객체를 먼저 로드하고, 그 후 서브쿼리를 사용하여 자식 객체를 로드할 때 적합
from sqlalchemy.orm import subqueryload
query = session.query(Parent).options(subqueryload(Parent.children))</code></pre>
<br>

<p><code>selectinload</code>: 관계된 객체를 별도의 select 문으로 로드</p>
<pre><code class="language-python"># 부모 객체가 여러개 있고 각 부모 객체에 대한 자식 객체를 한번의 쿼리로 로드할 때 유용
from sqlalchemy.orm import selectinload
query = session.query(Parent).options(selectinload(Parent.children))</code></pre>
<br>

<p><code>lazyload</code>: 객체가 실제로 액세스될 때까지 로드하지 않음</p>
<pre><code class="language-python"># 즉시 로딩이 필요하지 않고, 실제로 객체가 사용될 때 로드해도 문제가 없을 때 적합
# 특정 객체의 자식 객체를 사용하지 않을 가능성이 높을 때
from sqlalchemy.orm import lazyload
query = session.query(Parent).options(lazyload(Parent.children))</code></pre>
<br>

<p><code>immediateload</code>: 객체를 즉시 로드</p>
<pre><code class="language-python"># 특정 객체가 반드시 필요하며, 가능한 빨리 로드해야 할 때 사용
from sqlalchemy.orm import immediateload
query = session.query(Parent).options(immediateload(Parent.children))</code></pre>
<br>

<p><code>noload</code>: 관계된 객체를 전혀 로드하지 않음</p>
<pre><code class="language-python"># 특정 객체의 관련 데이터를 전혀 사용하지 않을 때
from sqlalchemy.orm import noload
query = session.query(Parent).options(noload(Parent.children))</code></pre>
<br>

<p><code>raiseload</code>: 관계된 객체를 로드하려고 할 때 예외를 발생 시킴</p>
<pre><code class="language-python"># 관계된 객체를 로드하지 않고자 할 때 이를 확실히 하기 위해 사용, 디버깅에 유용
from sqlalchemy.orm import raiseload
query = session.query(Parent).options(raiseload(Parent.children))</code></pre>
<br>

<p><code>contains_eager</code>: 이미 로드된 관계를 사용하여 eager loading을 수행</p>
<pre><code class="language-python"># 직접 작성한 쿼리에서 이미 로드된 데이터를 사용하고자 할 때 사용
from sqlalchemy.orm import contains_eager
query = session.query(Parent).join(Parent.children).options(contains_eager(Parent.children))</code></pre>
<br>

<p><code>load_only</code>: 특정 컬럼만 로드하여 필요한 데이터만 가져오도록 최적화</p>
<pre><code class="language-python"># 필요한 컬럼만 로드하여 쿼리 성능을 최적화하고자 할 때 사용
from sqlalchemy.orm import load_only
query = session.query(Parent).options(load_only(Parent.name, Parent.age))</code></pre>
<br>

<p><code>defer</code>: 특정 컬럼의 로딩을 지연 시킴</p>
<pre><code class="language-python"># 특정 컬럼을 나중에 필요할 때까지 로드하지 않고 지연시키고자 할 때 사용
from sqlalchemy.orm import defer
query = session.query(Parent).options(defer(Parent.large_blob_column))</code></pre>
<br>

<p><code>undefer</code>: 지연 로딩된 컬럼을 즉시 로드</p>
<pre><code class="language-python"># 지연 로딩된 컬럼을 즉시 로드해야 할 때 사용
from sqlalchemy.orm import undefer
query = session.query(Parent).options(undefer(Parent.large_blob_column))</code></pre>
<br>

<p><code>with_parent</code>: 부모 객체를 기준으로 관련된 객체를 로드</p>
<pre><code class="language-python"># 부모 객체를 기준으로 자식 객체를 로드하고자 할 때 사용
from sqlalchemy.orm import with_parent
query = session.query(Child).with_parent(parent_instance, &quot;children&quot;)</code></pre>
<br>

<p><code>defaultload</code>: 기본 로딩 전략을 적용, 이를 사용하여 중첩된 관계의 로딩 전략을 지정할 수 있음</p>
<pre><code class="language-python"># 중첩된 관계의 로딩 전략을 지정하고자 할 때 사용
from sqlalchemy.orm import defaultload
query = session.query(Parent).options(defaultload(Parent.children).joinedload(Child.toys))</code></pre>
<br>

<p><code>aliased</code>: 쿼리에서 사용되는 엔티티에 대해 별칭을 정의</p>
<pre><code class="language-python"># 복잡한 쿼리에서 엔티티의 별칭을 사용하고자 할 때, 동일한 테이블을 여러 번 조인해야 할 때
from sqlalchemy.orm import aliased
ParentAlias = aliased(Parent)
query = session.query(Parent).join(ParentAlias, Parent.children).filter(ParentAlias.name == &quot;John&quot;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Http Status Code] HTTP 상태 코드 설명]]></title>
            <link>https://velog.io/@cod_kms/HTTP-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%97%90%EB%9F%AC-%EC%BD%94%EB%93%9C-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@cod_kms/HTTP-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%97%90%EB%9F%AC-%EC%BD%94%EB%93%9C-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Tue, 07 Jan 2025 06:44:10 GMT</pubDate>
            <description><![CDATA[<h2 id="1xx-informational-정보-제공">1xx: Informational (정보 제공)</h2>
<pre><code>임시 응답으로, 현재 클라이언트의 요청은 처리 중이므로 계속 진행하라는 의미이다. HTTP 1.1 버전에서 추가되었다.</code></pre><br>

<h2 id="2xx-success-성공">2xx: Success (성공)</h2>
<pre><code>클라이언트의 요청이 서버에서 성공적으로 처리되었음을 의미한다.</code></pre><h4 id="200-ok-서버가-요청을-성공적으로-처리한-상태">200 OK: 서버가 요청을 성공적으로 처리한 상태</h4>
<h4 id="201-created-요청이-처리되어-새로운-리소스가-생성된-상태">201 Created: 요청이 처리되어 새로운 리소스가 생성된 상태</h4>
<h4 id="204-no-content-요청을-처리했으나-클라이언트에게-반환할-콘텐츠가-없음을-의미">204 No Content: 요청을 처리했으나 클라이언트에게 반환할 콘텐츠가 없음을 의미</h4>
<br>

<h2 id="3xx-redirection-리다이렉션">3xx: Redirection (리다이렉션)</h2>
<pre><code>요청을 완료하기 위해 추가적인 동작이 필요함을 나타낸다. 
일반적으로 서버 주소나 URI가 변경되었으므로 해당 주소로 다시 요청을 시도하라는 의미이다.</code></pre><br>

<h2 id="4xx-client-error-클라이언트-에러">4xx: Client Error (클라이언트 에러)</h2>
<pre><code>클라이언트 측에서 잘못된 요청을 보냈을 때 발생한다.
클라이언트의 요청 메시지 내용이 잘못된 경우를 의미한다.</code></pre><h4 id="400-bad-request-요청-구문이-잘못됨">400 Bad Request: 요청 구문이 잘못됨</h4>
<h4 id="401-unauthorized-리소스에-접근할-권한이-없음">401 Unauthorized: 리소스에 접근할 권한이 없음</h4>
<h4 id="403-forbidden-지정한-리소스에-대한-접근이-금지됨">403 Forbidden: 지정한 리소스에 대한 접근이 금지됨</h4>
<h4 id="404-not-found-요청한-리소스를-찾을-수-없음">404 Not Found: 요청한 리소스를 찾을 수 없음</h4>
<h4 id="415-unsupported-media-type-클라이언트가-지정한-미디어-타입을-서버가-지원하지-않음">415 Unsupported Media Type: 클라이언트가 지정한 미디어 타입을 서버가 지원하지 않음</h4>
<h4 id="422-unprocessable-entity-클라이언트가-보낸-xml-데이터는-구문이-맞지만-의미상-오류가-발생">422 Unprocessable Entity: 클라이언트가 보낸 XML 데이터는 구문이 맞지만, 의미상 오류가 발생</h4>
<br>

<h2 id="5xx-server-error-서버-에러">5xx: Server Error (서버 에러)</h2>
<pre><code>서버 측에서 문제가 발생하여 요청을 처리할 수 없을 때 발생한다.
서버의 부하, 데이터베이스 처리 오류, 예외 발생 등으로 인한 서버 문제를 의미한다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] Key (id)=(int) already exists]]></title>
            <link>https://velog.io/@cod_kms/Key-idint-already-exists</link>
            <guid>https://velog.io/@cod_kms/Key-idint-already-exists</guid>
            <pubDate>Tue, 07 Jan 2025 06:36:07 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-Shell">Traceback (most recent call last):
File &quot;&quot;, line 2116, in _exec_insertmany_context
dialect.do_execute(
File &quot;&quot;, line 924, in do_execute
cursor.execute(statement, parameters)
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint &quot;project_item_pkey&quot;
DETAIL:  Key (id)=(22) already exists.</code></pre>
<br>

<p>PgAdmin에서 데이터 restore 후 시퀀스가 안맞아서 나는 에러</p>
<p><code>SELECT setval(&#39;db명_id_seq&#39;, (SELECT MAX(id) FROM 테이블이름));</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] permission denied for schema public]]></title>
            <link>https://velog.io/@cod_kms/permission-denied-for-schema-public</link>
            <guid>https://velog.io/@cod_kms/permission-denied-for-schema-public</guid>
            <pubDate>Tue, 07 Jan 2025 06:32:59 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-bash">ERROR tests/test_api.py::TestSignUp::test_created - sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InsufficientPrivilege) permission denied for schema public
ERROR tests/test_api.py::TestSignUp::test_bad_request - sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InsufficientPrivilege) permission denied for schema public
ERROR tests/test_api.py::TestSignUp::test_exist_email - sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InsufficientPrivilege) permission denied for schema public</code></pre>
<br>
postgreSQL 사용자에게 superuser 권한 부여하여 에러 해결

<p><code>\du</code>
<code>alter user 사용자명 with superuser</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DRF] API(Application Programming Interface)]]></title>
            <link>https://velog.io/@cod_kms/APIApplication-Programming-Interface</link>
            <guid>https://velog.io/@cod_kms/APIApplication-Programming-Interface</guid>
            <pubDate>Tue, 07 Jan 2025 06:00:11 GMT</pubDate>
            <description><![CDATA[<h2 id="api">API</h2>
<blockquote>
<p>여러 프로그램과 데이터베이스, 그리고 기능들이 서로 통신할 수 있도록 돕는 매개체</p>
</blockquote>
<p>서비스 창구와 같은 여행을 수행하며, Client와 server 간 데이터를 주고받을 수 있도록 특정 형식에 맞춰 전달한다.
데이터베이스 자체는 아니지만, 서비스 요청에 따라 데이터나 기능을 제공하는 메신저이다.</p>
<br>

<h3 id="api-종류">API 종류</h3>
<p><strong>Private API</strong></p>
<ul>
<li>내부 API로, 기업이나 조직 내부에서만 사용한다.</li>
<li>외부 노출 없이 자체 제품 개발 및 운영 개선 목적으로 활용된다.</li>
</ul>
<p><strong>Public API</strong></p>
<ul>
<li>공개 API로, 누구나 접근이 가능하다.</li>
<li>완전 개방된 경우 Open API라고 부르며, 대표적이 예로 구글 API, 공공데이터포털 API가 있다.</li>
</ul>
<p><strong>Partner API</strong></p>
<ul>
<li>특정 비즈니스 파트너 간 데이터를 공유하기 위해 사용된다.</li>
<li>협약된 특정 사용자들만 접근할 수 있다.</li>
</ul>
<br>

<h3 id="api-장점">API 장점</h3>
<p><strong>데이터 접근의 표준화와 편의성</strong></p>
<ul>
<li>디바이스나 운영체제에 관계없이 일정한 조건만 만족하면 누구나 동일한 방식으로 액세스할 수 있다.</li>
<li>복잡한 로직 없이 기능적 API로 간단히 작업 가능하다.</li>
</ul>
<p><strong>자동화와 확장성</strong></p>
<ul>
<li>개발 워크플로우를 간소화하며, 애플리케이션 확장이 쉬워진다.</li>
</ul>
<p><strong>적용력</strong></p>
<ul>
<li>데이터 수집 및 전달에서 유연성을 제공하며, 협업 및 서비스 통합에 용이하다.</li>
</ul>
<br>

<h3 id="api-단점">API 단점</h3>
<p><strong>보안성 문제</strong></p>
<ul>
<li>API 게이트웨이가 단일 진입점이 되어 해커의 타겟이 될 수 있다.</li>
<li>HTTP 방식으로 동작하기 때문에 일부 기능이 제한될 수 있다.</li>
</ul>
<p><strong>표준 부재와 비용</strong></p>
<ul>
<li>API 설계에 공식 표준이 없어 관리가 어렵.</li>
<li>초기 개발 및 유지 관리에 높은 비용이 요구된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DRF] DRF (Django REST Framework) 기본 개념과 사용법]]></title>
            <link>https://velog.io/@cod_kms/DRF-Django-REST-Framework-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@cod_kms/DRF-Django-REST-Framework-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Tue, 07 Jan 2025 05:48:17 GMT</pubDate>
            <description><![CDATA[<h2 id="drf">DRF</h2>
<blockquote>
<p>Django 안에서 RESTfulAPI 서버를 쉽게 구축할 수 있도록 도와주는 오픈 소스 라이브러리</p>
</blockquote>
<h4 id="api-application-programming-interface">API (Application Programming Interface)</h4>
<p>데이터를 요청하고 전달하는 과정에서 클라이언트와 서버 간의 매개체 역할을 한다.
즉, API는 서비스 창구처럼 작동하여 데이터를 특정 형식에 맞게 전달한다.</p>
<h4 id="rest-representational-state-transfer">REST (Representational State Transfer)</h4>
<p>REST는 HTTP 프로토콜을 기반으로 자원을 관리하는 아키텍처 스타일이다.</p>
<ul>
<li>자원 (Resource): URL로 표현</li>
<li>행위 (Operation): HTTP 메서드 (GET, POST, PUT, PATCH, DELETE)등으로 정의</li>
<li>메세지 (Message): 요청(Request)과 응답(Response) 구조로 통신</li>
</ul>
<h4 id="rest-api">REST API</h4>
<p>REST 설계 원칙을 기반으로 만들어진 Web API를 RESTful API라고 한다.
이를 통해 프론트엔드와 백엔드가 효율적으로 소통이 가능하다.</p>
<h4 id="json-javascript-object-notation">Json (JavaScript Object Notation)</h4>
<p>Json은 데이터를 자바스크립트 객체 형태로 송수신하는 가벼운 문자열 데이터 표현식이다.</p>
<ul>
<li>Key-Value 형식으로 데이터를 표현</li>
<li>숫자, 문자열, Boolean, 배열, 객체 등을 지원</li>
<li>플랫폼과 언어에 독립적으로 다양한 시스템 간 데이터 교환이 용이<pre><code>{
  &quot;name&quot;: &quot;name&quot;,
  &quot;age&quot;: 25,
  &quot;gender&quot;: &quot;female&quot;,
  &quot;address&quot;: &quot;address 25&quot;,
  &quot;specialty&quot;: [&quot;coding&quot;, &quot;drf&quot;]
}</code></pre></li>
</ul>
<h4 id="serializer">Serializer</h4>
<p>Django의 DB 모델 데이터를 JSON 형태로 변환하는 역할을 한다.</p>
<ul>
<li>직렬화 (Serializer): 데이터를 송수신하거나 저장하기 위해 전송 가능한 형식으로 변환하는 과정</li>
<li>Django에서 Serializer는 모델 데이터를 JSON 형태로 변환할 때 주로 사용됨<pre><code class="language-python"># models.py
</code></pre>
</li>
</ul>
<p>from django.db import models</p>
<p>class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()</p>
<pre><code>```python
# serializers.py

from rest_framework import serializers

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = [&#39;title&#39;, &#39;content&#39;]</code></pre><pre><code class="language-python"># views.py

from .serializers import ArticleSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Article

class ArticleView(APIView):
    def get(self, request):
        queryset = Article.objects.all()
        serializer = ArticleSerializer(queryset, many=True)
        return Response(serializer.data)</code></pre>
<pre><code class="language-javascript"># result
[
  {
    &quot;title&quot;: &quot;hello&quot;,
    &quot;content&quot;: &quot;big world&quot;
  }
]</code></pre>
]]></description>
        </item>
    </channel>
</rss>