Pothos 및 Kysely를 사용하여 Type-safe GraphQL API를 구축하는 방법
34650 단어 tutorialgraphqlnodetypescript
소개
GraphQL API를 생성하는 두 가지 일반적인 방법은 스키마 우선과 코드 우선입니다. TypeScript 프로젝트에서 스키마 우선 접근 방식을 선호하는 경우 항상 api 스키마의 codegen을 사용할 수 있습니다. 그러나 코드 우선 접근 방식을 사용하여 API를 만드는 방법은 천 가지가 있습니다.
그리고 선택을 더욱 복잡하게 만들기 위해 JavaScript 커뮤니티에는 다른 커뮤니티와 비교할 때 많은 라이브러리가 있습니다. 그러나 최근에 TypeScript 커뮤니티에서 본 패턴은 더 나은 개발 경험을 제공하기 때문에 자동 데이터 유형 추론의 대중화입니다.
오늘은 무엇을 만들까요?
오늘의 기사에서는 Koa 라이브러리 및 GraphQL Yoga과 함께 Pothos 프레임워크를 사용하여 GraphQL API를 생성할 것입니다. 또한 전체가 TypeScript로 작성된 쿼리 빌더인 Kysely 을 사용합니다.
시작하기
첫 번째 단계로 프로젝트 디렉토리를 생성하고 해당 디렉토리로 이동합니다.
mkdir gql-ts-api
cd gql-ts-api
다음으로 TypeScript 프로젝트를 초기화합니다.
npm init -y
npm install typescript @types/node --save-dev
다음으로
tsconfig.json
파일을 만들고 다음 구성을 추가합니다.{
"compilerOptions": {
"target": "ESNext",
"lib": ["ESNext"],
"module": "ESNext",
"rootDir": "src",
"moduleResolution": "node",
"baseUrl": ".",
"types": ["node"],
"resolveJsonModule": true,
"allowJs": true,
"outDir": "dist",
"removeComments": true,
"isolatedModules": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
이제 필요한 종속성을 설치할 수 있습니다.
npm install koa graphql @graphql-yoga/node @pothos/core @pothos/plugin-simple-objects kysely better-sqlite3 --save
npm install @types/koa @types/better-sqlite3 ts-standard --save-dev
다음으로
package.json
에서 다음 속성을 추가합니다.{
"ts-standard": {
"noDefaultIgnore": false,
"ignore": [
"dist"
],
"project": "./tsconfig.json",
"report": "stylish"
}
}
프로젝트를 lint하고 싶을 때마다 다음 명령을 실행하십시오.
npx ts-standard --fix
데이터베이스 스키마 생성
프로젝트가 설정되면 손가락 베이스의 스키마를 정의하는 것으로 시작할 수 있으며 이를 위해
dog
및 name
와 같은 열을 포함하는 breed
라는 테이블을 만들 것입니다. 이 방법:// @/src/db/index.ts
import {
Kysely,
SqliteDialect,
Generated
} from 'kysely'
import SQLite from 'better-sqlite3'
interface DogTable {
id: Generated<number>
name: string
breed: string
}
interface Database {
dog: DogTable
}
export const db = new Kysely<Database>({
dialect: new SqliteDialect({
database: new SQLite('dev.db')
})
})
오늘 기사에서는 Kysely로 마이그레이션을 수행하지 않을 것이므로 앞에서 정의한 속성과 함께
dog
라는 테이블을 생성하는 것이 좋습니다.스키마 빌더 생성
SchemaBuilder 클래스는 GraphQL 스키마에 포함될 유형을 생성하는 데 사용됩니다. 그리고 거기에 정의된 유형은 컨텍스트와 같은 리졸버에서 유추되며, 이 외에도 필요한 플러그인을 등록할 수 있습니다.
// @/src/builder.ts
import SchemaBuilder from '@pothos/core'
import SimpleObjectsPlugin from '@pothos/plugin-simple-objects'
import { db } from './db'
interface Root<T> {
Context: T
}
export interface Context {
db: typeof db
}
const builder = new SchemaBuilder<Root<Context>>({
plugins: [SimpleObjectsPlugin]
})
builder.queryType({})
builder.mutationType({})
export { builder }
일부 유형 정의
이제 GraphQL API의 스키마에서 일부 유형을 정의할 수 있습니다. 먼저 반환될 데이터에 대한 일부 정보를 나타내는 객체를 생성합니다(이 문서의 경우 여러 리졸버 간에 공유됨).
// @/src/schema/typeDefs.ts
import { builder } from '../builder'
export const DogObjectType = builder.simpleObject('CreateDogResponse', {
fields: (t) => ({
id: t.id(),
name: t.string(),
breed: t.string()
})
})
export const DogObjectInput = builder.inputType('DogObjectInput', {
fields: (t) => ({
name: t.string({ required: true }),
breed: t.string({ required: true }),
id: t.int()
})
})
위의 코드에서 데이터 유형을 정의하지 않고 개체를 정의했지만 여전히 유형 안전성이 있습니다.
일부 필드 정의
다음 단계는 쿼리 및 변형과 같은 일부 필드를 스키마에 추가하는 것입니다. 각 리졸버에서 우리는 컨텍스트를 통해 데이터베이스에서 개체를 가져오고 필요한 작업을 수행합니다.
또한 인수뿐만 아니라 각 해석기의 반환을 정의하기 위해 생성된 유형을 사용할 것입니다.
// @/src/schema/resolvers.ts
import { builder } from '../builder'
import { DogObjectType, DogObjectInput } from './typeDefs'
builder.queryField('getDogs', (t) =>
t.field({
type: [DogObjectType],
resolve: async (root, args, ctx) => {
return await ctx.db.selectFrom('dog').selectAll().execute()
}
})
)
builder.queryField('getDog', (t) =>
t.field({
type: DogObjectType,
args: {
id: t.arg.int({ required: true })
},
resolve: async (root, args, ctx) => {
return await ctx.db.selectFrom('dog').selectAll().where('id', '=', args.id).executeTakeFirstOrThrow()
}
})
)
builder.mutationField('createDog', (t) =>
t.field({
type: DogObjectType,
args: {
input: t.arg({
type: DogObjectInput,
required: true
})
},
resolve: async (root, args, ctx) => {
return await ctx.db.insertInto('dog').values({
name: args.input.name,
breed: args.input.breed
}).returningAll().executeTakeFirstOrThrow()
}
})
)
builder.mutationField('updateDog', (t) =>
t.field({
type: DogObjectType,
args: {
input: t.arg({
type: DogObjectInput,
required: true
})
},
resolve: async (root, args, ctx) => {
const data = {
id: args.input.id as number,
name: args.input.name,
breed: args.input.breed
}
return await ctx.db.insertInto('dog').values(data)
.onConflict((oc) => oc.column('id').doUpdateSet(data))
.returningAll().executeTakeFirstOrThrow()
}
})
)
builder.mutationField('removeDog', (t) =>
t.field({
type: DogObjectType,
args: {
id: t.arg.int({ required: true })
},
resolve: async (root, args, ctx) => {
return await ctx.db.deleteFrom('dog').where('id', '=', args.id).returningAll().executeTakeFirstOrThrow()
}
})
)
우리는 이미 GraphQL 스키마와 관련된 많은 것을 정의했지만 코드 우선 스키마를 GraphQL 서버가 해석할 수 있는 무언가로 컴파일해야 합니다.
// @/src/schema/index.ts
import path from 'path'
import fs from 'fs'
import { printSchema, lexicographicSortSchema } from 'graphql'
import { builder } from '../builder'
import './resolvers'
export const schema = builder.toSchema({})
const schemaAsString = printSchema(lexicographicSortSchema(schema))
fs.writeFileSync(path.join(process.cwd(), './src/schema/schema.gql'), schemaAsString)
GraphQL 서버 생성
마지막으로 GraphQL 서버 구성을 포함할 api 항목 파일을 생성하기만 하면 됩니다. 이 파일에 우리가 생성한 스키마를 추가하고 Kysely 인스턴스를 API 컨텍스트에 추가합니다.
// @/src/main.ts
import Koa from 'koa'
import { createServer } from '@graphql-yoga/node'
import { schema } from './schema'
import { Context } from './builder'
import { db } from './db'
const app = new Koa()
const graphQLServer = createServer<Koa.ParameterizedContext>({
schema,
context: (): Context => ({ db })
})
app.use(async (ctx) => {
const response = await graphQLServer.handleIncomingMessage(ctx.req, ctx)
ctx.status = response.status
response.headers.forEach((value, key) => {
ctx.append(key, value)
})
ctx.body = response.body
})
app.listen(4000, () => {
console.log('Running a GraphQL API server at http://localhost:4000/graphql')
})
결론
늘 그렇듯이 기사가 마음에 드셨기를 바라며 기존 프로젝트에 도움이 되었거나 단순히 사용해 보고 싶으셨기를 바랍니다.
기사에서 잘못된 부분을 발견했다면 댓글로 알려주시면 수정하겠습니다. 마치기 전에 이 기사의 소스 코드에 액세스하려면 github 저장소에 대한 링크here를 남겨둡니다.
Reference
이 문제에 관하여(Pothos 및 Kysely를 사용하여 Type-safe GraphQL API를 구축하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/franciscomendes10866/how-to-build-a-type-safe-graphql-api-using-pothos-and-kysely-4ja3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)