Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Хранимые данные (persistent data) являются неотъемлемой частью современных веб-приложений. Они нужны нам для сохранения информации о пользователях, предоставления платежной информации и многого-многого другого. Теперь вы можете подключать свои любимые технологии хранения данных (Prisma, Mongoose, MySQL и другие) через npm и в Deno!
Этот пост продемонстрирует вам, как быстро начать работу в Deno со следующими npm-модулями:
Prisma
Mongoose
Apollo
Больше руководств по началу работы с npm-модулями для хранения данных вы можете найти в нашем мануале.
Повышенная безопасность хранения данных с Deno
Атаки через цепочку поставок (supply chain attacks) — известная проблема безопасности в npm. Node устанавливает и запускает npm-модули с доступом ко всему по умолчанию, что позволяет всего одной вредоносной зависимости незаметно скомпрометировать миллионы конечных пользователей.
Хранилище данных подвержено еще большему риску атак через цепочку поставок, поскольку к конфиденциальным производственным данным, необходимым для ведения бизнеса, можно получить доступ через переменные окружения.
Модель явного предоставления разрешений Deno гарантирует, что вы точно знаете, к чему вашим зависимостям требуется доступ. Система разрешений достаточно детализирована, чтобы вы могли предоставить доступ к переменным окружения, файловой системе и даже FFI.
Prisma
Prisma, современная ORM, способная похвастаться непревзойденным опытом разработки, была одним из наших наиболее востребованных модулей. Ниже приведено краткое руководство по началу работы с Prisma в Deno.
В следующем разделе показано, как быстро подключить Prisma к Deno.
Вы можете изучить исходный код здесь или посмотреть видеоруководство на нашем YouTube-канале.
Настройка приложения
Давайте создадим папку deno-prisma
и переместимся туда.
mkdir deno-prisma & cd deno-prisma
Затем запустим prisma init
с помощью Deno:
deno run --allow-read --allow-env --allow-write npm:prisma@^4.5 init
Это сгенерирует prisma/schema.prisma. Давайте обновим его следующим образом:
generator client {
provider = "prisma-client-js"
previewFeatures = ["deno"]
output = "../generated/client"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Dinosaur {
id Int @id @default(autoincrement())
name String @unique
description String
}
Prisma также должна была сгенерировать .env
файл с DATABASE_URL
. Давайте присвоим DATABASE_URL
строку подключения PostreSQL. В этом примере мы будем использовать бесплатную базу данных PostgreSQL от Supabase.
После того, как мы обновили .env
файл, нам нужно создадать схему базы данных в Prisma:
deno run npm:prisma@^4.5 db push
После этого нам нужно сгенерировать клиент Prisma для Data Proxy:
deno run npm:prisma@ ^4.5 generate --data-proxy
Настройка Prisma Data Platform
Чтобы использовать Prisma Data Platform, нам нужно создать и подключить репозиторий GitHub. Итак, давайте инициализируем локальный репозиторий, создадим новый репозиторий на GitHub, добавим удаленный источник и запушим локальный репозиторий.
После этого создайте бесплатную учетную запись Prisma Data Platform.
Кликните “New Project” и выберите “Import a Prisma Repository”.
Он запросит строку подключения PostgreSQL, которая должна быть в вашем .env
файле. Скопируйте ее сюда. Затем кликните “Create Project”.
Вы получите новую строку подключения, начинающуюся с prisma://
. Давайте присвоим ее DATABASE_URL
в вашем .env
файле, тем самым заменив нашу строку PostgreSQL из Supabase.
Использование Prisma и PrismaClient
Теперь вы сможете импортировать Prisma
и PrismaClient
в свой Deno-проект:
import { Prisma, PrismaClient } from "../generated/client/deno/edge.ts";
Далее вы можете заполнить свою базу данных, запросить данные и так далее.
Ознакомьтесь с нашим более подробным руководством по использованию Prisma или узнайте, как развернуть Prisma с помощью Deno Deploy.
Mongoose
Mongoose — популярная использующая схему библиотека, которая моделирует данные для MongoDB. Ниже приведено краткое руководство по началу работы с ней.
Вы можете изучить исходный код здесь или посмотреть видеоруководство на нашем YouTube-канале.
Определение модели
Давайте определим модель в Mongoose. В новый файл Dinosaur.ts добавим:
import { model, Schema } from "npm:mongoose@^6.7";
// Определение схемы.
const dinosaurSchema = new Schema({
name: { type: String, unique: true },
description: String,
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now },
});
// Проверки
dinosaurSchema.path("name").required(true, "Dinosaur name cannot be blank.");
dinosaurSchema.path("description").required(
true,
"Dinosaur description cannot be blank.",
);
// Экспорт модели.
export default model("Dinosaur", dinosaurSchema);
Создание нового динозавтра
Давайте создадим новый файл main.ts
, который будет:
подключаться к MongoDB
создавать нового
Dinosaur
извлекать динозавра с именем "Deno"
console.log
полученного динозавра
import mongoose from "npm:mongoose@^6.7";
import Dinosaur from "./model/Dinosaur.ts";
await mongoose.connect("mongodb://localhost:27017");
// Создание нового динозавра.
const deno = new Dinosaur({
name: "Deno",
description: "The fastest dinosaur ever lived.",
});
// Внедрение deno.
await deno.save();
// Поиск по имени Deno.
const denoFromMongoDb = await Dinosaur.findOne({ name: "Deno" });
console.log(
`Finding Deno in MongoDB -- \n ${denoFromMongoDb.name}: ${denoFromMongoDb.description}`,
);
Вывод должен быть следующим:
Finding Deno in MongoDB --
Deno: The fastest dinosaur ever lived.
Отлично!
Ознакомьтесь с нашим более подробным руководством по работе с Mongoose.
Apollo
Apollo — это GraphQL-сервер, который можно настроить за считанные минуты и использовать с существующим источником данных (или REST API). Вы можете подключить к нему любой GraphQL-клиент, чтобы получить доступ к данным и воспользоваться всеми преимуществами проверки типов и эффективного фетчинга.
Давайте настроим и запустим простой сервер Apollo, который позволит нам запрашивать некоторые локальные данные. Для этого нам понадобятся только три файла:
schema.ts
, что настроить нашу модель данных,resolvers.ts
для настройки того, как мы собираемся заполнять поля данных в нашей схемеи наш
main.ts
где будет запускаться сервер.
И начнем мы с их создания:
touch schema.ts resolvers.ts main.ts
Давайте разберемся с настройкой каждого из них.
Посмотреть код можно здесь.
Определяем наши данные с помощью schema.ts
Файл schema.ts
описывает наши данные. В данном случае наши данные представляют собой список динозавров. Мы хотим, чтобы наши пользователи могли получить имя и краткое описание каждого динозавра. На языке GraphQL это означает, что Dinosaur
— это наш тип, а name
(имя) и description
(описание) — это наши поля. Мы также можем определить тип данных для каждого поля. В данном случае оба поля будут строками.
Здесь мы также описываем запросы, которые мы разрешаем для наших данных, используя специальный тип Query GraphQL. У нас будут два запроса:
dinosaurs
, который получает список всех динозавровdinosaur
, который принимает имя динозавра в качестве аргумента и возвращает информацию об этом типе динозавра
Мы собираемся экспортировать все это в наши typeDefs
переменные:
export const typeDefs = `
type Dinosaur {
name: String
description: String
}
type Query {
dinosaurs: [Dinosaur]
dinosaur(name: String): Dinosaur
}
`;
Если бы мы хотели записать данные, нам бы также нужно было описать мутацию для этого. Мутации (Mutation) — это то, как вы записываете данные с помощью GraphQL. Поскольку мы используем здесь статический набор данных, мы не будем писать ничего такого.
Заполнение данными в resolvers.ts
Резолвер отвечает за заполнение данных для каждого запроса. Здесь у нас есть наш список динозавров, и все, что будет делать резолвер, это либо а) передавать весь этот список клиенту, если пользователь формирует запрос dinosaurs
, либо б) передавать только одного из них, если пользователь запрашивает dinosaur
.
const dinosaurs = [
{
name: "Aardonyx",
description: "An early stage in the evolution of sauropods.",
},
{
name: "Abelisaurus",
description: '"Abel\'s lizard" has been reconstructed from a single skull.',
},
];
export const resolvers = {
Query: {
dinosaurs: () => dinosaurs,
dinosaur: (_: any, args: any) => {
return dinosaurs.find((dinosaur) => dinosaur.name === args.name);
},
},
};
В последнем случае мы передаем аргументы от клиента в функцию, чтобы сопоставить полученное имя с именем в нашем наборе данных.
Настройка main.ts
В наш main.ts
мы будем импортировать ApolloServer
, graphql
и наши typeDef
из схемы и наших резолверов:
import { ApolloServer } from "npm:@apollo/server@^4.1";
import { startStandaloneServer } from "npm:@apollo/server@^4.1/standalone";
import { graphql } from "npm:graphql@^16.6";
import { typeDefs } from "./schema.ts";
import { resolvers } from "./resolvers.ts";
const server = new ApolloServer({
typeDefs,
resolvers,
});
const { url } = await startStandaloneServer(server, {
listen: { port: 8000 },
});
console.log(`Server running on: ${url}`);
Мы передаем наши typeDefs
и resolvers
в ApolloServer
, необходимые для запуска нашего нового сервера. Наконец, startStandaloneServer
— это вспомогательная функция, позволяющая быстро запустить сервер.
Запуск сервера
Все, что осталось сделать, это запустить сервер:
deno run --allow-net --allow-read --allow-env main.ts
Вы должны увидеть Server running on: 127.0.0.1:8000
в вашем терминале. Если вы перейдете по этому адресу, вы увидите сэндбокс Apollo, где мы можем ввести наш запрос dinosaurs
:
query {
dinosaurs {
name
description
}
}
Это вернет наш набор данных:
{
"data": {
"dinosaurs": [
{
"name": "Aardonyx",
"description": "An early stage in the evolution of sauropods."
},
{
"name": "Abelisaurus",
"description": "\"Abel's lizard\" has been reconstructed from a single skull."
}
]
}
}
Или, если нам нужен только один dinosaur
:
query {
dinosaur(name:"Aardonyx") {
name
description
}
}
Что возвращает:
{
"data": {
"dinosaur": {
"name": "Aardonyx",
"description": "An early stage in the evolution of sauropods."
}
}
}
Потрясающе!
Ознакомьтесь с нашим более подробным руководством по работе с Apollo.
Что дальше?
В этом посте мы продемонстрировали, как начать работу с Prisma, Mongoose и Apollo. У нас также есть руководства по другим npm-модулям хранения данных, таким как PlanetScale, Redis и MySQL2, и мы продолжим добавлять новые.
Что-то не получается? Обращайтесь за помощью в наш Discord.
Приглашаем всех желающих на открытое занятие «Хуки и мемоизация», на котором участники научатся эффективно использовать возможности React.js и избегать лишних рендеров. Регистрация открыта на странице курса "React.js Developer".