Мой хороший друг порекомендовал курс Уэса Боса Advance React and GraphQL. Курс преподавался на JavaScript, но, поскольку тогда я только изучал TypeScript, я хотел сделать это на TypeScript для практики.
Хотя я мог добавлять типы почти ко всему, меня очень беспокоил тот факт, что мои преобразователи не были типизированы. После долгих поисков в Google я наконец нашел способ печатать мои серверные распознаватели. В этой статье будет рассказано обо всем, что я делал, от начала до конца, так что расслабьтесь, расслабьтесь и давайте начнем печатать!
Настраивать
В этом проекте используются Prisma и Генератор кода GraphQL.
Сначала создайте каталог для вашего сервера:
mkdir server; cd server; yarn init -y
Во-вторых, установите эти пакеты:
yarn add graphql-cli prisma-binding yarn add -D typescript
Инициализация Prisma
Затем запустите prisma init
и следуйте инструкциям. Вы можете использовать существующую базу данных, создать новую или использовать их демонстрационную базу данных.
Для этого урока я собираюсь использовать демонстрационную базу данных:
На следующих нескольких экранах просто следуйте инструкциям. Когда вы перейдете на этот экран, выберите Don't generate
, так как мы будем вручную создавать .graphql
схему.
После этого вы увидите 2 новых файла: prisma.yml
и datamodel.prisma
. Давайте откроем upprisma.yml
.
Генерация схемы Prisma и Local GraphQL
Добавьте в свой prisma.yml
следующие строки кода:
# this is what's generated endpoint: ${env:PRISMA_ENDPOINT} datamodel: datamodel.prisma # add these hooks: post-deploy: - graphql get-schema -p prisma
Это означает, что всякий раз, когда вы запускаете prisma deploy
, эти обработчики после развертывания всегда будут запускаться после. Но прежде чем мы запустим это, давайте создадим .graphqlconfig.yml
в корневом каталоге:
### /.graphqlschema.yml projects: app: # path to YOUR gql schema schemaPath: 'src/schema.graphql' extensions: endpoints: # your graphql endpoint (not playground url!) default: 'http://localhost:5000' prisma: # where you want to generate the PRISMA graphql schema schemaPath: 'src/generated/prisma.graphql' extensions: # path to the prisma.yml prisma: 'src/prisma/prisma.yml'
Я упростил приведенный выше файл с помощью комментариев, чтобы вы могли создавать файлы, подходящие для вашего каталога, сколько захотите. Обратите внимание, что проекты app
и prisma
имеют отдельные схемы GraphQL. Проект app
- это то, что ваш сервер будет использовать. В проекте prisma
используется автоматически созданная схема GraphQL Prisma.
Генерация схемы Prisma
После этого запустите yarn graphql get-schema -p prisma
. Ваша схема Prisma GraphQL теперь создается там, где вы ее указали! Откройте его и осмотритесь.
Создайте схему GraphQL для своего сервера
Теперь создайте схему GraphQL вашего сервера. Чтобы использовать схему Prisma, создайте schema.graphql
файл и импортируйте схему Prisma следующим образом:
### src/schema.graphql # import * from './generated/prisma.graphql type Query { # Since the Prisma schema is imported, # we don't need to specify User type again! # Just call it here and it will automagically do the rest! fetchUser(id: ID!): User }
Файлы GraphQL используют комментарии для импорта.
Теперь вы можете запустить prisma deploy
в своем терминале, и он автоматически сгенерирует для вас схему Prisma. Вы можете внести изменения в свой datamodel.prisma
, добавив дополнительные типы:
type User { id: ID! @id name: String! @unique email: String! @unique password: String! } type Item { id: ID! @id name: String! description: String! price: Int! }
Запустите prisma deploy
, и вы увидите соответствующие изменения в prisma.graphql
файле.
Создание схемы Prisma TypeScript
Пришло время сгенерировать нашу схему Prisma в TypeScript. Откройте prisma.yml
и добавьте новый хук после развертывания:
endpoint: ${env:PRISMA_ENDPOINT} datamodel: datamodel.prisma hooks: post-deploy: - graphql get-schema -p prisma - graphql codegen # add this line
В .graphqlconfig.yml
добавьте расширение codegen к проекту prisma
:
projects: app: schemaPath: 'src/schema.graphql' extensions: endpoints: default: 'http://localhost:5000' prisma: schemaPath: 'src/generated/prisma.graphql' extensions: prisma: 'src/prisma/prisma.yml' # add these below codegen: generator: prisma-binding language: typescript # path to the Prisma schema input: 'src/generated/prisma.graphql' output: # where to generate the TypeScript Prisma schema binding: 'src/generated/prisma.ts'
Теперь запустите yarn graphql codegen
или prisma deploy
и вуаля! Создан prisma.ts
. Откройте его и осмотритесь. Это похоже на огромный беспорядок кода, но вы всегда можете запустить Prettier после этого, чтобы все очистить. Обратите внимание на указанную переменную экспорта Prisma
.
Создание типа контекста преобразователя
Помните именованную переменную экспорта Prisma
из сгенерированного prisma.ts
? Здесь мы добавляем его в контекст наших преобразователей! Создайте context.ts
:
// ./src/resolvers/context.ts import { Prisma } from '../generated/prisma' export type Context = { db: Prisma }
Настройка генератора кода GraphQL
Вот где действительно проявляется генератор кода GraphQL! Установите следующие пакеты:
yarn add -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers
Выполните следующую команду:
graphql-codegen init
Ответьте как таковые на следующие вопросы:
Последние 4 вопроса действительно касаются того, как вы хотите структурировать свой сервер. Мои текущие ответы просты. Это сгенерирует codegen.yml
(в зависимости от того, какое имя файла вы указали для вывода).
Указание типа контекста для генератора кода GraphQL
Откройте codegen.yml
и добавьте еще строки кода:
### /codegen.yml overwrite: true schema: './src/schema.graphql' documents: null generates: src/resolvers/types.ts: plugins: - 'typescript' - 'typescript-resolvers' # add these below config: skipTypename: true # This path is RELATIVE to where you will generate your output!! # In this case, it looks for the context.ts in src/resolvers # './context#Context' means it will look for a Type/Interface with the name 'Context' in context.s contextType: './context#Context' hooks: afterAllFileWrite: - prettier --write # optional
Обратите внимание на contextType
в разделе config
:
contextType
ищет файл, относительный к тому месту, где типы преобразователя генерируются (выводятся).- В этом случае, поскольку наш
types.ts
создается вsrc/resolvers
, он будет искатьcontext.ts
в том же каталоге. ./context#Context
ищетtype
илиinterface
с именемContext
вcontext.ts
файле.- В таком случае помните наш
export type Context
ранее? Он будет искать это.
Кроме того, skipTypename
- это полностью ваш звонок. Теперь запустите yarn codegen
(или имя скрипта, которое вы дали ему во время установки). Откройте сгенерированный types.ts
и внимательно осмотритесь.
Настройка наших резолверов
Наконец-то наступил момент, которого мы все ждали! Давайте настроим наши запросы и изменения. Кроме того, перед продолжением добавьте больше запросов / мутаций в свой schema.graphql
.
Настройка запросов
Создайте query.ts
в src/resolvers
:
### src/schema.graphql type Query { fetchUser(id: ID!): User fetchItems(where: ItemWhereUniqueInput): [Item]! } // ./src/resolvers/query.ts import { QueryResolvers } from './types' const Query: QueryResolvers = { fetchItems: { fragment: '', resolve: async (parent, { where }, ctx, info) => { return await ctx.db.query.items({where: where}, info) } }, fetchUser: { fragment: '', resolve: async (parent, { id }, ctx, info) => { return await ctx.db.query.user({ where: { id } }, info) } } } export default Query
Как вы увидите, редактор теперь может определять тип args
и ctx
каждого запроса:
Тип QueryResolvers
также знает, какие запросы у меня есть в моем schema.graphql
:
На мой взгляд, лучшая часть этого заключается в том, что аргумент ctx
теперь полностью типизирован:
Настройка мутаций
Давайте также быстро наберем мутации:
### src/schema.graphql input createItemInput { name: String! description: String! price: Int! } type Mutation { createItem(data: createItemInput!): Item! // ./src/resolvers/mutation.ts import { MutationResolvers } from './types' const Mutation: MutationResolvers = { createItem: { fragment: '', resolve: async (parent, { data }, ctx, info) => { const { name, description, price } = data return await ctx.db.mutation.createItem({ data: { name, description, price } }, info) } } } export default Mutation
Как видите, при деструктуризации объекта data
он также знает, какие аргументы мы ему передаем!
Заключение
Как видите, распознаватели с типобезопасностью - вещь прекрасная. Он помогает определить, какие у вас есть запросы / мутации, какие аргументы они принимают, и, что наиболее важно, дает вам полностью типизированный объект ctx
. Всякий раз, когда вы вносите изменения в свой schema.graphql
, вы можете просто запустить сгенерированный скрипт codegen
, чтобы обновить все ваши преобразователи!