보안 Node.js GraphQL API를 만드는 방법
게시 됨: 2022-03-11이 기사에서는 안전한 Node.js GraphQL API를 만드는 방법에 대한 빠른 가이드를 제공하는 것을 목표로 합니다.
다음과 같은 몇 가지 질문이 떠오를 수 있습니다.
- GraphQL API를 사용하는 목적은 무엇입니까?
- GraphQL API란 무엇입니까?
- GraphQL 쿼리란 무엇입니까?
- GraphQL의 이점은 무엇입니까?
- GraphQL이 REST보다 낫습니까?
- Node.js를 사용하는 이유는 무엇입니까?
그것들은 모두 유효한 질문이지만 대답하기 전에 웹 개발의 현재 상태에 대한 간략한 개요를 살펴봐야 합니다.
- 오늘날 찾을 수 있는 거의 모든 솔루션은 일종의 API(응용 프로그래밍 인터페이스)를 사용합니다.
- 페이스북이나 인스타그램과 같은 소셜 네트워크만 사용하더라도 API를 사용하는 프론트엔드에는 여전히 연결되어 있습니다.
- 궁금한 점이 있으면 Netflix, Spotify 및 YouTube와 같은 서비스를 포함하여 거의 모든 온라인 엔터테인먼트 서비스가 다른 종류의 API를 사용한다는 것을 알게 될 것입니다.
거의 모든 시나리오에서 자세히 알 필요가 없는 API를 찾을 수 있습니다. 예를 들어 API가 어떻게 구축되었는지 알 필요도 없고 이전과 동일한 기술을 사용할 필요도 없습니다. 자신의 시스템에 통합할 수 있습니다. 제공되는 API를 사용하면 특정 기술 스택에 의존하지 않고도 서비스와 클라이언트가 모두 통신할 수 있는 공통 표준에서 서비스 간에 통신하는 방법을 제공할 수 있습니다.
잘 구조화된 API를 사용하면 여러 종류의 클라이언트와 프런트 엔드 애플리케이션에 서비스를 제공할 수 있는 견고하고 유지 관리 가능하며 확장 가능한 API를 가질 수 있습니다.
GraphQL API란 무엇 입니까 ?
GraphQL은 API용 쿼리 언어로 Facebook 내부용으로 개발되었으며 2015년 공개용으로 게시되었습니다. 읽기, 쓰기 및 실시간 업데이트를 지원합니다. 또한 오픈 소스이며 일반적으로 REST 및 기타 아키텍처와 비교됩니다. 간단히 말해서 다음을 기반으로 합니다.
- GraphQL 쿼리 - 이를 통해 클라이언트는 데이터 수신 방법을 읽고 조작할 수 있습니다.
- GraphQL Mutations - 서버에 데이터를 쓰는 방법입니다. 시스템에 데이터를 쓰는 방법에 대한 GraphQL 규칙입니다.
이 기사는 GraphQL API를 구축하고 사용하는 방법에 대한 간단하면서도 실제적인 시나리오를 보여주기 위한 것이지만 GraphQL에 대한 자세한 소개는 제공하지 않을 것입니다. GraphQL 팀이 포괄적인 문서를 제공하고 GraphQL 소개에서 몇 가지 모범 사례를 나열하기 때문에 그 이유는 간단합니다.
GraphQL 쿼리란 무엇입니까?
앞에서 설명한 것처럼 쿼리는 클라이언트가 API에서 데이터를 읽고 조작할 수 있는 방법입니다. 개체 유형을 전달하고 다시 받을 필드 유형을 선택할 수 있습니다. 간단한 쿼리는 다음과 같습니다.
query{ users{ firstName, lastName } }
이 쿼리에서 우리는 사용자 스키마의 모든 사용자에게 접근하려고 하지만 firstName
및 lastName
만 수신합니다. 이 쿼리의 결과는 예를 들어 다음과 같습니다.
{ "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }
클라이언트 사용을 위해 아주 간단합니다.
GraphQL API를 사용하는 목적은 무엇입니까?
API를 만드는 목적은 다른 외부 서비스에 의해 통합될 수 있는 SaaS(Software as a Service)를 갖는 기능입니다. 단일 프론트엔드에서 애플리케이션을 사용하더라도 이 프론트엔드를 외부 서비스로 간주할 수 있으며, 이를 위해 API를 통해 둘 간의 통신이 제공되면 다른 프로젝트에서 작업할 수 있습니다.
대규모 팀에서 작업하는 경우 프론트엔드 및 백엔드 팀을 분할하여 동일한 기술을 사용하고 작업을 더 쉽게 만들 수 있습니다. API를 설계할 때 프로젝트에 더 잘 맞는 것과 원하는 솔루션에 더 가까운 것을 선택하는 것이 중요합니다.
이 기사에서는 GraphQL을 사용하는 API를 구축하기 위한 스켈레톤에 초점을 맞출 것입니다.
GraphQL이 REST보다 낫습니까?
그것은 약간의 경찰 아웃 일지 모르지만 나는 그것을 도울 수 없습니다. 그것은 .
GraphQL은 여러 시나리오에 매우 잘 맞는 접근 방식입니다. REST는 여러 시나리오에서도 입증된 아키텍처 접근 방식입니다. 요즘에는 하나가 다른 것보다 나은 이유 또는 GraphQL 대신 REST만 사용해야 하는 이유를 설명하는 수많은 기사가 있습니다. 또한 내부적으로 GraphQL을 사용하고 API의 끝점을 REST 기반 아키텍처로 유지 관리할 수 있는 여러 가지 방법이 있습니다.
가장 좋은 지침은 각 접근 방식의 이점을 알고, 만들고 있는 솔루션을 분석하고, 팀이 해당 솔루션을 얼마나 편안하게 사용하고 있는지 평가하고, 팀이 학습하고 최신 정보를 얻을 수 있도록 안내할 수 있는지 여부를 평가하는 것입니다. 접근 방식 중에서 선택하기 전에 속도를 빠르게 합니다.
이 기사는 GraphQL과 REST에 대한 주관적인 비교라기 보다는 실용적인 가이드에 가깝습니다. 이 둘에 대한 자세한 비교를 읽고 싶다면 다른 기사 GraphQL vs. REST - A GraphQL Tutorial을 확인하는 것이 좋습니다.
오늘 기사에서는 Node.js를 사용하여 GraphQL API를 만드는 데 중점을 둘 것입니다.
왜 Node.js를 사용합니까?
GraphQL에는 사용할 수 있는 여러 라이브러리가 있습니다. 이 기사의 목적을 위해 우리는 널리 사용되는 Node.js와 Node.js를 통해 개발자가 서버 측 개발에 익숙한 프론트 엔드 구문을 사용할 수 있기 때문에 Node.js와 함께 JavaScript를 사용하는 아이디어를 사용하기로 결정했습니다.
다른 Toptal 엔지니어링 블로그 기사: Node.js에서 보안 REST API 생성에서 설명한 것과 유사한 REST 기반 API를 사용한 접근 방식과 비교하는 것도 유용합니다. 이 기사는 또한 Node.js를 Express와 함께 사용하여 이러한 두 접근 방식 간의 몇 가지 차이점을 비교할 수 있는 골격 REST API를 개발하는 방법을 보여줍니다. Node.js는 또한 확장 가능한 네트워크 애플리케이션, 글로벌 커뮤니티 및 npm 웹사이트에서 찾을 수 있는 여러 오픈 소스 라이브러리로 설계되었습니다.
이번에는 GraphQL, Node.js, Express로 스켈레톤 API를 구축하는 방법을 보여드리겠습니다!
GraphQL 튜토리얼 실습
앞서 설명한 대로 GraphQL API에 대한 기본 아이디어를 구축할 것이며 계속 진행하기 전에 Node.js 및 Express의 기본 사항을 알아야 합니다. 이 GraphQL 예제를 위해 만든 프로젝트의 소스 코드는 여기에서 볼 수 있습니다.
우리는 두 가지 유형의 리소스를 처리할 것입니다.
- 기본 CRUD를 처리할 사용자 .
- GraphQL의 힘을 더 많이 보여주기 위해 약간의 세부 사항이 있는 제품 .
사용자는 다음 구조를 포함합니다.
- ID
- 이름
- 성
- 이메일
- 비밀번호
- 권한 수준
제품에는 다음 구조가 포함됩니다.
- ID
- 이름
- 설명
- 가격
코딩 표준은 이 프로젝트에 TypeScript를 사용할 것입니다. 소스 파일에서 TypeScript로 코딩을 시작하도록 모든 것을 구성할 수 있습니다.
코딩하자!
먼저 최신 Node.js 버전이 설치되어 있는지 확인하십시오. 게시 당시 현재 버전은 Nodejs.org에 따라 10.15.3입니다.
프로젝트 초기화
node-graphql
이라는 이름의 새 폴더에서 시작하겠습니다. 여기에서 터미널 또는 Git CLI 콘솔을 열고 npm init
명령을 사용하여 마법을 시작할 수 있습니다.
종속성 및 TypeScript 구성
프로세스 속도를 높이려면 Git 리포지토리에서 package.json
을 다음으로 바꾸면 필요한 모든 종속성이 포함되어야 합니다.
{ "name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": { "tsc": "tsc", "start": "npm run tsc && node ./build/app.js" }, "author": "", "license": "ISC", "dependencies": { "@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4" }, "devDependencies": { "tslint": "^5.14.0", "typescript": "^3.3.4000" } }
업데이트된 package.json
으로 터미널을 다시 누르고 npm install
을 사용하세요. Node.js 및 Express 내에서 이 GraphQL API를 실행하는 데 필요한 모든 종속성을 설치합니다.
다음 부분은 TypeScript 모드를 구성하는 것입니다. 다음이 포함된 루트 폴더에 tsconfig.json
이라는 파일이 필요합니다.
{ "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }
이 구성에 대한 코드 논리는 앱 폴더에 있습니다. 거기에서 app.ts
파일을 만들고 기본 테스트를 위해 거기에 다음 코드를 추가할 수 있습니다.
console.log('Hello Graphql Node API tutorial');
구성에 따라 이제 npm start
를 실행하고 빌드를 기다리고 모든 것이 제대로 작동하는지 테스트할 수 있습니다. 터미널 콘솔에 "Hello GraphQL Node API 튜토리얼"이 표시되어야 합니다. 뒷 장면에서 구성은 기본적으로 TypeScript 코드를 순수 JavaScript로 컴파일한 다음 build
폴더에서 빌드를 실행합니다.
이제 GraphQL API의 기본 골격을 구성해 보겠습니다. 프로젝트를 시작하기 위해 세 가지 기본 가져오기를 추가합니다.
- 표현하다
- Express-graphql
- Graphql 도구
모든 것을 함께 시작합시다.
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';
이제 우리는 약간의 코딩을 시작할 수 있어야 합니다. 다음 단계는 Express에서 앱을 처리하고 다음과 같은 기본 GraphQL 구성을 처리하는 것입니다.
import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools'; const app: express.Application = express(); const port = 3000; let typeDefs: any = [` type Query { hello: String } type Mutation { hello(message: String) : String } `]; let helloMessage: String = 'World!'; let resolvers = { Query: { hello: () => helloMessage }, Mutation: { hello: (_: any, helloData: any) => { helloMessage = helloData.message; return helloMessage; } } }; app.use( '/graphql', graphqlHTTP({ schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true }) ); app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));
우리가 하는 일은:

- Express 서버 앱에 대해 포트 3000을 활성화합니다.
- 빠른 예로 사용하려는 쿼리와 변형을 정의합니다.
- 쿼리 및 돌연변이가 작동하는 방식을 정의합니다.
좋습니다. 하지만 typeDefs 및 resolver는 물론 쿼리 및 변형과의 관계는 어떻게 됩니까?
- typeDefs - 쿼리 및 변형에서 기대할 수 있는 스키마의 정의입니다.
- 확인자 - 필드 또는 필수 매개변수에 대한 기대 대신 쿼리 및 돌연변이가 작동하는 방식에 대한 기능과 동작을 정의합니다.
- 쿼리 - 서버에서 읽고자 하는 "가져오기"입니다.
- 돌연변이 - 자체 서버에 있는 모든 데이터에 영향을 미칠 요청입니다.
이제 npm start 를 다시 실행하여 무엇이 있는지 살펴보겠습니다. 앱이 다음 메시지와 함께 실행될 것으로 예상합니다. Node Graphql API가 포트 3000에서 수신 대기 중입니다!
이제 http://localhost:3000/graphql을 통해 자체 서버에서 GraphQL API를 쿼리하고 테스트할 수 있습니다.
좋습니다. 이제 "hello"로 정의된 첫 번째 쿼리를 작성할 수 있습니다.
typeDefs
에서 정의한 방식은 페이지에서 쿼리를 작성하는 데 도움이 될 수 있습니다.
훌륭합니다. 하지만 어떻게 값을 변경할 수 있습니까? 돌연변이!
이제 돌연변이로 메모리 내 값을 변경할 때 어떤 일이 발생하는지 봅시다.
이제 GraphQL Node.js API를 사용하여 기본 CRUD 작업을 수행할 수 있습니다. 이제 코드를 진행해 보겠습니다.
제품
제품의 경우 제품이라는 모듈을 사용합니다. 이 기사를 단순화하기 위해 우리는 데모용으로 메모리 내 데이터베이스를 사용할 것입니다. 우리는 제품을 관리하기 위한 모델과 서비스를 정의할 것입니다.
우리의 모델은 다음을 기반으로 합니다.
export class Product { private id: Number = 0; private name: String = ''; private description: String = ''; private price: Number = 0; constructor(productId: Number, productName: String, productDescription: String, price: Number) { this.id = productId; this.name = productName; this.description = productDescription; this.price = price; } }
GraphQL과 통신할 서비스는 다음과 같이 정의됩니다.
export class ProductsService { public products: any = []; configTypeDefs() { let typeDefs = ` type Product { name: String, description: String, id: Int, price: Int } `; typeDefs += ` extend type Query { products: [Product] } `; typeDefs += ` extend type Mutation { product(name:String, id:Int, description: String, price: Int): Product! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.products = () => { return this.products; }; resolvers.Mutation.product = (_: any, product: any) => { this.products.push(product); return product; }; } }
사용자
사용자의 경우 제품 모듈과 동일한 구조를 따릅니다. 우리는 사용자를 위한 모델과 서비스를 가질 것입니다. 모델은 다음과 같이 정의됩니다.
export class User { private id: Number = 0; private firstName: String = ''; private lastName: String = ''; private email: String = ''; private password: String = ''; private permissionLevel: Number = 1; constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.password = password; this.permissionLevel = permissionLevel; } }
한편, 우리의 서비스는 다음과 같습니다:
const crypto = require('crypto'); export class UsersService { public users: any = []; configTypeDefs() { let typeDefs = ` type User { firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String } `; typeDefs += ` extend type Query { users: [User] } `; typeDefs += ` extend type Mutation { user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.users = () => { return this.users; }; resolvers.Mutation.user = (_: any, user: any) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64"); user.password = hash; this.users.push(user); return user; }; } }
참고로 이 링크에서 소스 코드를 사용할 수 있습니다.
이제 코드를 재생하고 테스트할 수 있습니다. npm start
를 실행해 봅시다. 서버는 포트 3000에서 실행됩니다. 이제 테스트를 위해 http://localhost:3000/graphql에서 GraphQL에 액세스할 수 있습니다.
제품 목록에 항목을 추가하기 위해 변형을 시도해 보겠습니다.
작동하는지 테스트하기 위해 이제 제품에 대한 쿼리를 사용하지만 id
, name
및 price
만 수신합니다.
query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }
그리고 그게 다야; 제품이 예상대로 작동합니다. 이제 우리는 원한다면 플레이하고 필드를 전환할 수 있습니다. 설명을 추가할 수 있습니다.
query{ products{ id, name, description, price } }
이제 제품에 대한 설명을 볼 수 있습니다. 이제 사용자를 사용해 보겠습니다.
mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }
그리고 쿼리는 다음과 같을 것입니다:
query{ users{ id, firstName, lastName, password, email } }
다음과 같은 응답으로:
{ "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }
이제 GraphQL 골격이 준비되었습니다! 여기에서 유용하고 완전한 기능의 API를 향한 수많은 단계가 있지만 이제 기본 핵심이 설정되었습니다.
요약 및 최종 생각
요약하자면 이 기사는 GraphQL Node.js API 개발에 관한 기본 정보가 많이 포함되어 있어 상당히 큽니다.
지금까지 다룬 내용을 검토해 보겠습니다.
- Node.js를 Express 및 GraphQL과 함께 사용하여 GraphQL API 구축
- 기본 GraphQL 사용
- 쿼리 및 변형의 기본 사용법
- 프로젝트의 모듈을 만드는 기본 접근 방식
- GraphQL API 테스트
개발 측면에 더 집중하기 위해 다음과 같이 간략하게 요약할 수 있는 몇 가지 중요한 항목을 피했습니다.
- 새 항목에 대한 유효성 검사
- 일반 오류 서비스로 오류를 올바르게 처리합니다.
- 사용자가 일반 서비스와 함께 각 요청에서 사용할 수 있는 필드 유효성 검사
- API를 보호하기 위해 JWT 인터셉터를 추가합니다.
- 보다 효과적인 접근 방식으로 비밀번호 해시를 처리합니다.
- 단위 및 통합 테스트를 추가합니다.
이 Git 링크에 전체 소스 코드가 있음을 기억하십시오. 자유롭게 사용하고, 포크하고, 이슈를 열고, 풀 리퀘스트를 하고, 함께 플레이하세요! 이 기사의 모든 표준과 제안은 돌에 새겨져 있지 않다는 점에 유의하십시오.
이것은 자신의 GraphQL API 설계를 시작하는 데 사용할 수 있는 많은 접근 방식 중 하나일 뿐입니다. 또한 GraphQL을 더 자세히 읽고 탐색하여 제공해야 하는 내용과 API를 더욱 개선할 수 있는 방법을 배우십시오.