Хранимые данные (persistent data) являются неотъемлемой частью современных веб-приложений. Они нужны нам для сохранения информации о пользователях, предоставления платежной информации и многого-многого другого. Теперь вы можете подключать свои любимые технологии хранения данных (Prisma, Mongoose, MySQL и другие) через npm и в Deno!
Этот пост продемонстрирует вам, как быстро начать работу в Deno со следующими npm-модулями:
Больше руководств по началу работы с 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».
ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/712614/
Добавить комментарий