소개
2000년도 중반부터 본격적으로 웹개발을 시작하여 현재까지 프리랜서 개발자로 활동하고 있습니다. 약5년간 Amplix BI 솔루션 실무자 교육을 진행하고 개발을 지원하며 새로운 기술을 효율적으로 전달하는 것에 대한 많은 경험과 고민을 했습니다.
현재는 개발 업무와 함께 개발자들에게 도움이 될만한 웹관련 분야의 새로운 기술을 찾고 강좌와 책을 통해 공유하고 있습니다.
현) 프리랜서
전) (주) 비즈플러그 전략솔루션 사업부 팀장
전) (주) 퍼니몽키스 위니스토리 서비스 개발 팀장
youtube: https://www.youtube.com/channel/UC3cJspjF4TRTyD_RS0azeaw
email: freeseamew@gmail.com
blog1: https://medium.com/freeseamew
blog2: https://dev.to/freeseamew
강좌 목록
출간도서
강의
로드맵
전체 1수강평
- Svelte REST-API 프로젝트
- 차세대 Node.js 백엔드 서버 개발(Fastify & Prisma & Typescript와 함께하는)
- GraphQL 완전정복 (키오스크를 만들며 배우는 풀스택 과정) - [2024 부분 리뉴얼]
게시글
질문&답변
Swagger 문서 접근 권한
swagger에 비밀번호를 적용하는 방법으로 basic-auth라는 것을 이용하는 방법이 있습니다.설정에 관하여 간단하게 설명을 드리도록 하겠습니다.우선 fastify/basic-auth를 다음과 같이 설치해 주시기 바랍니다.참고로 강좌의 fastify버전의 경우 v4버전이기 때문에 basic-auth는 5버전을 사용하셔야 합니다. npm i @fastify/basic-auth@5 다음으로 main.ts를 열고 필요한 설정을 해야 합니다 .fastify에서 필요한 FastifyRequest, FastifyReply, HookHandlerDoneFunction을 불러오고여기에 설치한 BasicAuth를 가져와 줍니다.여기에 validate함수를 만들고 여기에서 아이디, 패스워드를 확인하도록 설정합니다다음으로 register로 basicAuth를 등록하고 validate 함수를 연동해 줍니다.이제 addHook에 onRequest를 설정하고접근하는 url이 documentation일 경우 이 basic-auth가 작동하게 만들면 되겠습니다.여기서 주의할 점으로 기존 예제와 달리 main.ts에서 register로 각종 플러그인을 등록할 경우 await을 사용해야 한다는 것입니다.이부분을 유의해서 사용해 보시기 바랍니다. main.tsimport Fastify from 'fastify' import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox' import type { FastifyCookieOptions } from '@fastify/cookie' import fasstifyCookie from '@fastify/cookie' import routes from './routes' import { SECRET_KEY } from './lib/constants' import { currentlyAuthPlugin } from './plugin/authPlugin' import { checkStartupUser, checkStartupArticle } from './startup' import cors from '@fastify/cors' import fastifySwagger from '@fastify/swagger' import fastifySwaggerUi from '@fastify/swagger-ui' import { swaggerConfig, swaggerUiConfig } from './config/swagger' //추가코드 import { FastifyRequest, FastifyReply, HookHandlerDoneFunction } from 'fastify' import BasicAuth from '@fastify/basic-auth'; const fastify = Fastify({ logger: true, // https: { // key: fs.readFileSync('./server.key'), // cert: fs.readFileSync('./server.crt'), // } }).withTypeProvider() // fastify.get('/ping', async (request, reply) => { // return 'pong\n' // }) // 각 register등록시 await 사용 await fastify.register(cors, { origin: true, // Access-Control-Allow-Origin credentials: true, //Access-Control-Allow-Credentials }) await fastify.register(fastifySwagger, swaggerConfig) await fastify.register(fastifySwaggerUi, swaggerUiConfig) await fastify.register(fasstifyCookie, { secret: SECRET_KEY, } as FastifyCookieOptions ) await fastify.register(currentlyAuthPlugin) await fastify.register(routes) // basic-auth with swagger 추가 코드 const authenticate = {realm: 'Westeros'} await fastify.register(BasicAuth, {validate, authenticate}) function validate (username:string, password:string, req:FastifyRequest, reply:FastifyReply, done:HookHandlerDoneFunction) { if (username === 'admin' && password === '1111') { done() } else { done(new Error('Winter is coming')) } } fastify.addHook("onRequest", (req:FastifyRequest, res:FastifyReply, done:HookHandlerDoneFunction) => { if (req.url.startsWith(`/documentation`)) { fastify.basicAuth(req, res, done); } else { done(); } }) const start = async () => { try { await checkStartupUser() await checkStartupArticle() await fastify.listen({port: 8083}) console.log(`Server Start!!`) } catch(error) { fastify.log.error(error) process.exit(1) } } start()
- 0
- 1
- 11
질문&답변
Window 환경에서 meteor 설치하는 부분에 대해 실습환경 구축 부분에 추가내용이 없습니다.
windows, mac 모두 npm 명령어로 인스톨이 가능합니다.하지만 얼마전 meteor version3로 업데이트 되어 강좌에서 사용한 version2와 호환문제가 있을 수 있습니다.그래서 다음과 같이 meteor뒤에 @2를 작성해서 meteor version2를설치하시기 바랍니다. npm install -g meteor@2
- 0
- 3
- 45
질문&답변
앱에 refreshToken을 전송할때 궁금한점이 있습니다.
개인적으로 저는 보통 웹 기반의 서비스와 하이브리드앱 제작을 주로 해서 네이티브에 대한 지식은 한정적이라는 것을 우선 양해 부탁드리겠습니다.jwt의 핵심은 결국 json 키를 이용한 인증이기 때문에 cookie를 사용할 수 없는 환경이라면 access token과 마찬가지로 json 파일을 header등에 실어 보내는 방법이 가장 심플한 방법일 것으로 예상됩니다.대신 키의 저장을 ios나 안드로이드에서 좀 더 안전한 곳에 보관할 수 있는 방법을 찾아 관리를 해야 할 것으로 예상됩니다.
- 0
- 2
- 58
질문&답변
리액트에서 적용할 때 질문있습니다.
제가 react를 써본지 오래 되서 정확히 어떤 부분을 어떻게 적용해야 하는지에 대해서 정확하게 알려드리기는 힘들지만 제가 알고 있는 부분에서 제 의견을 말씀드리겠습니다.우선 긍정적으로 검토가 가능한 부분은 현재 apollo-client에서 메인으로 지원하는 프런트엔드는 react가 된다는 점입니다.아래 링크를 보시면 apollo-client를 react로 어떻게 사용하는 것인지에 대한 전반적인 정보를 얻을 수 있을 것입니다.https://www.apollographql.com/docs/react/get-started또 svelte에서의 steore는 react에서 비슷한 개념으로 redux나 recoil 등 전역 상태 관리 라이브러리를 사용하셔야 할 것 같습니다. 비슷한 패턴으로 react를 작성하기 위해서는 이부분을 참고해서 백엔드서버로 부터 가져온 데이터를 이 전역 스토어에 저장하고 이를 불러 사용하는 패턴으로 사용하면 되지 않을까 생각됩니다.
- 0
- 1
- 86
질문&답변
Upload, 파일사이즈 코드 질문있습니다.
mutation schema를 보면 file의 타입이 sclar로 정의된 Upload로 만든 것을 볼 수 있습니다.여기서 이 Upload를 graphql-upload의 GraphQLUpload로 맵핑 시켜주어야 하는데이를 위해 필요한 코드가 바로 Upload: GraphQLUpload, 이부분입니다. scalar Upload type File { fileName: String fileType: String filePath: String } type Mutation { addCategory(categoryName: String): ID updateCategory(_id: ID, categoryName: String): ID deleteCategory(_id: ID): ID addItem(itemName: String, itemPrice: Int, itemImage: String, itemCategoryId: ID): Item updateItem(_id: ID, itemName: String, itemPrice: Int, itemImage: String, itemCategoryId: ID): Item deleteItem(_id: ID): ID uploadFile(file: Upload): File } 스트림스트림의 경우 메모리 효율성 보다는 nodejs의 스레드의 한계 때문에 사용하는 개념입니다.node는 기본적으로 멀티스레드가 아닌 단일 스레드이기 때문에 파일 처리와 같이 많은 시간이 걸리는 작업을 할 경우 작업을 하는 일꾼인 스레드가 이를 계속 잡고 있으면 모든 기능이 정지해 버리는 상태가 될 수 있습니다.그래서 파일 업로드와 같은 작업의 경우 한번에 모든 일처리를 끝내기 보다 작은 사이즈로 잘라서 조금씩 처리하는 것이 효율적이게 됩니다.프론트엔드의 경우는 브라우저에서 작동하지만 업로드된 이미지 처리의 경우는 서버에서 작동하게 되는데 특정 작업으로 서버의 스레드가 멈추게 되면 서비스 전체가 멈추게 될 위험이 있기 때문에 스트림과 같은 기능이 필요한 것입니다.또 압축의 경우 이와는 조금 다른 개념이기때문에 효율을 높이기 위해서라면 이둘을 같이 사용할 수 있다면 해보는 것도 좋을 것 같습니다.
- 0
- 1
- 106
질문&답변
이벤트 함수 on, handle 어떤 기준으로 정하는걸까요?
저같은 경우 일단 해당 강좌를 만들 당시에는함수 앞에 on을 붙이는 경우는 ui에서 호출되는 함수에 대해서 on을 붙였습니다 .현재는 on대신에 handle을 붙여 사용하고 있습니다.결론적으로 저의 경우 그래서 on과 handle의 차이는 없고 ui에서 호출되는 함수의 경우에만on또는 handle을 붙여서 해당 함수의 역할을 쉽게 알 수 있도록 사용하고 있습니다.이런 규칙의 경우 두루 살펴 보신다음에 사용하시기 편한 것을 쓰면 되고 대신 통일성은 중요하니 이부분을 유의해서 사용하시기를 추천드립니다.
- 0
- 1
- 148
질문&답변
itemForm에서 Modal바인딩 질문있습니다.
위의 내용의 경우는 svelte의 store라는 것 때문입니다.아래 내용의 경우 writable스토어를 작성하는데 이 writable의 초기값을 false로 설정한 부분이 되겠습니다.writable스토어의 경우 다음과 같이 초기값을 설정하고 사용하게 됩니다.지금은 boolean으로 설정했지만 여기에 숫자, 문자 그리고 객체등의 값을 초기화 해서 사용할 수 도 있습니다.또 초기에 설정된 값의 내용은 변경 가능하지만 타입은 변경이 안됩니다.그래서 wratable(false)이렇게 설정하면 이 스토어는 boolean타입의 스토어가 된다고 보시면 됩니다. (타입스크립트에서는 이부분이 좀 더 명확해 지긴 합니다. )writable 스토어는 svelte프레임워크의 한가지 기능이고 아래는 그 사용법이라고 기억하시면 되겠습니다.그리고 이렇게 설정된 스토어의 값은 ‘$스토어이름’ 이런식으로 값을 불러 사용하면 됩니다.참고로 이 스토어는 리엑티브적으로 작동합니다. 그래서 이 값을 어딘가에서 변경시키면 이 값을 불러 사용하는 전역에서 이 값을 참고해서 변화가 일어납니다. 이는 프런트엔드에서 아주많이 사용되는 패턴입니다.이부분이 잘 이해사 되지 않으신다면 아래 챕터를 한번 더 보시기를 추천드리겠습니다.‘섹션7. Frontend 개발 -개발 준비 및 기본 설정 - Svelte store’ const { subscribe, set } = writable(false) 또 const { subscribe, set } 이 문법의 경우 js의 비구조화 할당이라는 기능이 됩니다.즉 다음과 같이 정의된 objec에서 a, b값을 가져오는 방법이 됩니다.const object = { a: 1, b: 2 }; const { a, b } = object; console.log(a); // 1 console.log(b); // 2 writable의 경우에 updqte, set, 등이 정의 되어 있으니 이를 가져와 사용하기 위한 준비라고 보면 되겠습니다.
- 1
- 1
- 91
질문&답변
css 파일 질문있습니다
boxicon을 따로 폴더를 만든 이유는 제 기억으로는 font파일을 인식해서 icon들을 사용했었기 때문인 걸로 기억합니다. 설명에 있겠지만 meteor에서 public폴더의 경우 여기에 파일을 넣으면 /폴더/파일명 이런 url로 접근이 그낭해서 예전 meteor를 사용할 때는 이렇게 사용한 것으로 기억하고 있습니다.이를 위해서 따로 스토리북을 설정한 것을 없고 요즘에는 또 다른 방식으로 사용하고 있습니다현재는 lucide라는 플러그인을 주로 사용하는데 boxicon과 비슷한 아이콘 묶음 이라고 보시면 되고js 플러그인을 가져오는 것 처럼 그냥 import해서 사용할 수 있는 것이 좋아 이것을 많이 사용하고 있습니다https://lucide.dev/guide/packages/lucide-svelte그리고 css관리 방법의 경우 이건 개발자나 팀마다 특성이 달라 어느 방법이 최적이라고 말씀드리기는 어렵고 일단 저는 현재 bootstrap을 사용하진 않고 tailwindcss 라는 것을 사용하고 있다고 알려드립니다.tailwind의 경우 딱히 어떻게 기본 디자인이 정의되어 있다기 보다 그냥 css의 모든 요소를 css class화 시켜서 바로바로 그냥 불러 사용할 수 있는 방식입니다.한번 검색해서 보시면 다양한 자료가 있으니 어떤 제품인지 아시게 될 것입니다.
- 0
- 1
- 73
질문&답변
섹션7 디자인요소배치 이후 흰색화면..
작성하신 apollo-client.js 에 몇군대 오타가 있는 것 같습니다 우선 httprLink라는 import를 지우고(아마도 httpLink를 잘 못 표기한 것 같습니다. ),authLink에서 ApolloClient라고 되어 있는 곳을 ApolloLink로 변경하시기 바랍니다. import { ApolloClient, InMemoryCache, split, HttrpLink, // 이부분 삭제 ApolloLink, from, HttpLink, } from '@apollo/client' import { GraphQLWsLink } from '@apollo/client/link/subscriptions' import { getMainDefinition } from '@apollo/client/utilities' import { createClient } from 'graphql-ws' const httpLink = new HttpLink({ uri: 'http://localhost:3000/graphql', }) const wsLink = new GraphQLWsLink( createClient({ url: 'ws://localhost:3000/graphql', }), ) // 다음 ApolloClient를 ApolloLink로 변경 const authLink = new ApolloClient((operation, forward) => { return forward(operation) }) // 분기처리 서버쪽에서 subscription를 구독하는거면 true를 리턴해서 wsLink로 연결해줌 const link = split( ({ query }) => { const { kind, operation } = getMainDefinition(query) return kind === 'OperationDefinition' && operation === 'subscription' }, wsLink, httpLink, // uploadLink ) const client = new ApolloClient({ link: from([authLink, link]), cache: new InMemoryCache(), }) export default client
- 0
- 1
- 96
질문&답변
accessToken과 리프레시토큰 구현
일단 refresh 토큰을 이용한 경우는 제 다른 강좌에서 확인할 수 있습니다.'Svelte REST-API 프로젝트'라는 강좌인데 무료로 제공되는 강좌이니 이부분 참고해보시기 바랍니다.코드만 보기 원하시는 경우 아래 링크를 참고해서 보시면 되겠습니다.프런트코드: https://github.com/freeseamew/SLOG-FRONTEND-SVELTE백엔드코드:https://github.com/freeseamew/SLOG-FASTIFY-PRISMA-SERVER/tree/master참고해서 구현해 보시고 혹시 의문이 생기는 부분이 있으면 다시 문의 해주시기 바랍니다.감사합니다.
- 0
- 2
- 117