One place for hosting & domains

      PostgreSQL

      Создание REST API с помощью Prisma и PostgreSQL


      Автор выбрал Diversity in Tech Fund для получения пожертвования в рамках программы Write for DOnations.

      Введение

      Prisma — это набор инструментов для работы с базой данных с открытым исходным кодом. Он включает три основных инструмента:

      • Prisma Client: конструктор автоматически генерируемых типобезопасных запросов для Node.js и TypeScript.
      • Prisma Migrate: система моделирования данных и миграции, поддерживающая декларативный подход.
      • Prisma Studio: графический пользовательский интерфейс для просмотра и редактирования данных в вашей базе данных.

      Эти инструменты направлены на повышение производительности разработчика приложения при работе с базой данных. Одним из главных преимуществ Prisma является уровень абстракции, который она предоставляет: вместо формирования сложных SQL запросов или миграций схемы БД, разработчики приложения могут рассуждать о своих данных более интуитивно понятным образом, используя Prisma для работы с базой данных.

      В этом обучающем руководстве мы напишем REST API для небольшого приложения для ведения блога на TypeScript с помощью Prisma и базы данных PostgreSQL. Вы настроите локальную базу данных PostgreSQL с помощью Docker и реализуете маршруты REST API с помощью Express. После выполнения руководства у вас будет работающий на вашем локальном компьютере веб-сервер, который будет отвечать на различные HTTP запросы, а также выполнять чтение и запись в базу данных.

      Предварительные требования

      Для выполнения инструкций данного руководства требуется следующее:

      Базовое знакомство с TypeScript и REST API будет полезно, но не обязательно для выполнения данного руководства.

      Шаг 1 — Создание проекта TypeScript

      В этом шаге мы настроим простой проект TypeScript с помощью npm. Этот проект послужит основой для REST API, который вы будете создавать при выполнении данного руководства.

      Во-первых, создайте новый каталог для вашего проекта:

      Затем перейдите в этот каталог и инициализируйте создание пустого проекта npm. Обратите внимание, что опция -y здесь означает, что вы хотите пропустить интерактивные запросы команды. Чтобы просмотреть запросы, удалите -y из команды:

      Дополнительную информацию об этих запросах вы можете найти в шаге 1 руководства Использование модулей Node.js с npm и package.json.

      Вы получите примерно следующий вывод с ответами по умолчанию:

      Output

      Wrote to /.../my-blog/package.json: { "name": "my-blog", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      Эта команда создает файл package.json с минимальным содержанием, который вы будете использовать в качестве файла конфигурации для вашего проекта npm. Теперь вы готовы к настройке TypeScript в вашем проекте.

      Выполните следующую команду для простой настройки TypeScript:

      • npm install typescript ts-node @types/node --save-dev

      Эта команда устанавливает три пакета в качестве зависимостей разработки в вашем проекте:

      • typescript: набор инструментов TypeScript.
      • ts-node: пакет для запуска приложений TypeScript без предварительной компиляции в JavaScript.
      • @types/node: определения типов TypeScript для Node.js.

      В качестве последнего шага необходимо добавить файл tsconfig.json, чтобы гарантировать корректность настройки TypeScript для приложения, которое вы будете создавать.

      Сначала запустите следующую команду для создания файла:

      Добавьте в файл следующий код JSON:

      my-blog/tsconfig.json

      {
        "compilerOptions": {
          "sourceMap": true,
          "outDir": "dist",
          "strict": true,
          "lib": ["esnext"],
          "esModuleInterop": true
        }
      }
      

      Сохраните и закройте файл.

      Это стандартная и минимальная конфигурация для проекта TypeScript. Если вы хотите узнать об отдельных свойствах файла конфигурации, всю необходимую информацию вы можете найти в документации TypeScript.

      Вы настроили простой проект TypeScript с помощью npm. После этого вы должны будете настроить свою базу данных PostgreSQL с помощью Docker и подключить Prisma к этой базе данных.

      Шаг 2 — Настройка Prisma с PostgreSQL

      В этом шаге мы установим Prisma CLI, создадим первоначальный файл схемы Prisma и настроим PostgreSQL с помощью Docker, после чего нужно будет подключить ее к Prisma. Схема Prisma — это основной файл конфигурации для настройки Prisma, который содержит схему вашей базы данных.

      Начните с установки Prisma CLI, воспользовавшись следующей командой:

      • npm install @prisma/cli --save-dev

      Рекомендуется использовать локальную установку Prisma CLI для вашего проекта (а не глобальную установку). Это помогает избежать конфликтов версий при наличии нескольких проектов Prisma на вашем компьютере.

      Далее вам нужно настроить вашу базу данных PostgreSQL с помощью Docker. Создайте новый файл Docker Compose с помощью следующей команды:

      Добавьте следующий код во вновь созданный файл:

      my-blog/docker-compose.yml

      version: '3.8'
      services:
        postgres:
          image: postgres:10.3
          restart: always
          environment:
            - POSTGRES_USER=sammy
            - POSTGRES_PASSWORD=your_password
          volumes:
            - postgres:/var/lib/postgresql/data
          ports:
            - '5432:5432'
      volumes:
        postgres:
      

      Данный файл Docker Compose настраивает базу данных PostgreSQL, доступ к которой можно получить через порт 5432 контейнера Docker. Обратите внимание, что в настоящее время для базы данных установлены следующие учетные данные: sammy (пользователь) и your_password (пароль). Вы можете изменить эти учетные данные и указать предпочитаемые имя пользователя и пароль. Сохраните и закройте файл.

      После выполнения этих действий вы можете перейти к запуску сервера базы данных PostgreSQL с помощью следующей команды:

      Вывод этой команды будет выглядеть примерно следующим образом:

      Output

      Pulling postgres (postgres:10.3)... 10.3: Pulling from library/postgres f2aa67a397c4: Pull complete 6de83ca23e55: Pull complete . . . Status: Downloaded newer image for postgres:10.3 Creating my-blog_postgres_1 ... done

      Вы можете проверить, работает ли сервер базы данных, воспользовавшись следующей командой:

      Вы получите примерно следующий вывод:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8547f8e007ba postgres:10.3 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp my-blog_postgres_1

      После запуска сервера базы данных вы сможете создать вашу настройку Prisma. Запустите следующую команду в Prisma CLI:

      Результат будет выглядеть следующим образом:

      Output

      ✔ Your Prisma schema was created at prisma/schema.prisma. You can now open it in your favorite editor.

      Обратите внимание, что рекомендуется использовать префикс npx в каждом вызове Prisma CLI. Это гарантирует, что будет использоваться именно локальная установка клиента.

      После запуска команды Prisma CLI создает новую папку с именем prisma в вашем проекте. Она содержит два следующих файла:

      • schema.prisma: главный файл конфигурации для вашего проекта Prisma (он будет включать вашу модель данных).
      • .env: файл dotenv для определения URL-адреса для подключения к базе данных.

      Чтобы гарантировать, что Prisma будет знать расположение вашей базы данных, откройте файл .env и измените значение переменной среды DATABASE_URL.

      Сначала откройте файл .env:

      Теперь вы можете задать значение переменной среды следующим образом:

      my-blog/prisma/.env

      DATABASE_URL="postgresql://sammy:your_password@localhost:5432/my-blog?schema=public"
      

      Убедитесь, что вы можете изменить учетные данные для БД на данные, указанные в файле Docker Compose. Дополнительную информацию о формате URL-адреса подключения см. в документации Prisma.

      После выполнения этих действий сохраните и закройте файл.

      В этом шаге вы настроили свою базу данных PostgreSQL с помощью Docker, установили Prisma CLI и подключили Prisma к базе данных с помощью переменной среды. В следующем разделе вы определите модель данных и создадите таблицы вашей базы данных.

      Шаг 3 — Определение модели данных и создание таблиц базы данных

      В этом шаге вы определите вашу модель данных в файле схемы Prisma. Эта модель данных затем будет перенесена на базу данных с помощью Prisma Migrate, которая будет генерировать и отправлять SQL инструкции для создания таблиц, соответствующих вашей модели данных. Поскольку вы создаете приложение для ведения блога, основными сущностями приложения будут пользователи и посты.

      Prisma использует свой собственный язык моделирования данных для определения формы данных вашего приложения.

      Сначала откройте файл schema.prisma с помощью следующей команды:

      • nano prisma/schema.prisma

      Теперь добавьте в файл следующие определения модели. Вы можете поместить модели в нижней части файла сразу после блока generator client:

      my-blog/prisma/schema.prisma

      . . .
      model User {
        id    Int     @default(autoincrement()) @id
        email String  @unique
        name  String?
        posts Post[]
      }
      
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
        author    User?   @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-ru)
        authorId  Int?
      }
      

      Сохраните и закройте файл.

      Вы определяете две модели: User и Post. Каждая из этих моделей имеет ряд полей, которые представляют свойства модели. Модели будут отображаться в таблицах базы данных, а поля представляют отдельные столбцы.

      Обратите внимание на связь один-ко-многим между двумя моделями, определяемую связанными полями posts и author в таблицах User и Post. Это означает, что один пользователь может быть связан с несколькими постами.

      После получения этих моделей вы можете создать соответствующие таблицы в базе данных с помощью Prisma Migrate. В терминале запустите следующую команду:

      • npx prisma migrate save --experimental --create-db --name "init"

      Эта команда создает новую миграцию в вашей файловой системе. Ниже приводится краткое описание трех опций, предоставляемых командой:

      • --experimental: обязательная опция, поскольку Prisma Migrate находится в настоящее время в экспериментальном состоянии.
      • --create-db: дает Prisma Migrate возможность создать базу данных с именем my-blog, которое указано в URL-адресе подключения.
      • --name "init": указывает имя миграции (будет использоваться при присвоении имени папке миграции, создаваемой в вашей файловой системе).

      Вывод этой команды будет выглядеть примерно следующим образом:

      Output

      New datamodel: // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @default(autoincrement()) @id email String @unique name String? posts Post[] } model Post { id Int @default(autoincrement()) @id title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-ru) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      Вы можете ознакомиться с созданными миграционными файлами в каталоге prisma/migrations.

      Чтобы запустить миграцию для вашей базы данных и создать таблицы для ваших моделей Prisma, запустите следующую команду в терминале:

      • npx prisma migrate up --experimental

      Вывод должен выглядеть следующим образом:

      Output

      . . . Checking the datasource for potential data loss... Database Changes: Migration Database actions Status 20200811140708-init 2 CreateTable statements. Done 🚀 You can get the detailed db changes with prisma migrate up --experimental --verbose Or read about them here: ./migrations/20200811140708-init/README.md 🚀 Done with 1 migration in 206ms.

      Prisma Migrate генерирует инструкции SQL, необходимые для выполнения миграции, и отправляет их базе данных. Ниже приводятся SQL инструкции, которые создают таблицы:

      CREATE TABLE "public"."User" (
        "id" SERIAL,
        "email" text  NOT NULL ,
        "name" text   ,
        PRIMARY KEY ("id")
      )
      
      CREATE TABLE "public"."Post" (
        "id" SERIAL,
        "title" text  NOT NULL ,
        "content" text   ,
        "published" boolean  NOT NULL DEFAULT false,
        "authorId" integer   ,
        PRIMARY KEY ("id")
      )
      
      CREATE UNIQUE INDEX "User.email" ON "public"."User"("email")
      
      ALTER TABLE "public"."Post" ADD FOREIGN KEY ("authorId")REFERENCES "public"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE
      

      В этом шаге вы определили вашу модель данных в схеме Prisma и создали соответствующие таблицы базы данных с помощью Prisma Migrate. В следующем шаге вы установите Prisma Client для вашего проекта, чтобы вы могли отправлять запросы базе данных.

      Шаг 4 — Знакомство с запросами Prisma Client в форме простого скрипта

      Prisma Client — это инструмент для автоматической генерации типобезопасных запросов, который вы можете использовать для программного чтения и записи данных в базу данных в приложении на базе Node.js или TypeScript. Вы будете использовать его для доступа к базе данных в рамках ваших маршрутов REST API в качестве замены для традиционных ORM, простых запросов SQL, собственных слоев доступа к данным или любого другого метода работы с базой данных.

      В этом шаге вы установите Prisma Client и познакомитесь с запросами, которые он позволяет отправлять. Прежде чем реализовать маршруты для вашего REST API в следующих шагах, вы должны будете познакомиться с запросами Prisma Client в форме простого исполняемого скрипта.

      Перейдите к установке Prisma Client для вашего проекта, открыв терминал и установив пакет npm Prisma Client:

      • npm install @prisma/client

      Затем создайте новый каталог с именем src, который будет содержать исходные файлы:

      Теперь создайте файл TypeScript внутри нового каталога:

      Все запросы Prisma Client возвращают промисы, которые вы можете ожидать в своем коде. Поэтому вы должны отправлять запросы внутри асинхронной функции.

      Добавьте следующий шаблонный код с асинхронной функцией, выполняемой в вашем скрипте:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        // ... your Prisma Client queries will go here
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      Ниже приводится короткое пояснения шаблонного кода:

      1. Импорт конструктора PrismaClient из ранее установленного пакета npm @prisma/client.
      2. Создание объекта PrismaClient с помощью вызова конструктора и получения экземпляра с именем prisma.
      3. Определение асинхронной функции с именем main, куда вы позже будете добавлять запросы Prisma Client.
      4. Вызов функции main вместе с перехватом любых возможных исключений, а также гарантия того, что Prisma Client будет закрывать все открытые подключения к базе данных с помощью вызова prisma.disconnect().

      Получив в распоряжение функцию main, вы можете начинать добавлять запросы Prisma Client в скрипт. Измените содержание файла index.ts, которое должно выглядеть следующим образом:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        const newUser = await prisma.user.create({
          data: {
            name: 'Alice',
            email: 'alice@prisma.io',
            posts: {
              create: {
                title: 'Hello World',
              },
            },
          },
        })
        console.log('Created new user: ', newUser)
      
        const allUsers = await prisma.user.findMany({
          include: { posts: true },
        })
        console.log('All users: ')
        console.dir(allUsers, { depth: null })
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      В этом коде вы используете два запроса Prisma Client:

      • create: создает новую запись User. Обратите внимание, что вы используете вложенную запись, что означает, что вы создаете записи User и Post в одном запросе.
      • findMany: считывает все существующие записи User из базы данных. Вы указываете опцию include, которая дополнительно загружает связанные записи Post для каждой записи User.

      Теперь запустите скрипт с помощью следующей команды:

      В терминале вы получили следующий вывод:

      Output

      Created new user: { id: 1, email: 'alice@prisma.io', name: 'Alice' } [ { id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [ { id: 1, title: 'Hello World', content: null, published: false, authorId: 1 } ] }

      Примечание: если вы используете графический пользовательский интерфейс для базы данных, то сможете проверить, были ли созданы записи, посмотрев таблицы User и Post. Также вы можете просмотреть данные с помощью Prisma Studio, запустив команду npx prisma studio --experimental.

      Вы успешно воспользовались Prisma Client для чтения и записи данных в вашей базе данных. В оставшихся шагах вы будете применять эти новые знания для реализации маршрутов на образце REST API.

      Шаг 5 — Реализация вашего первого маршрута REST API

      В этом шаге вы установите Express для вашего приложения. Express — это популярный веб-фреймворк для Node.js, который вы будете использовать для имплементации ваших маршрутов REST API в рамках данного проекта. Первый маршрут, который вы будете реализовать, позволит вам получить всех пользователей из API с помощью запроса GET. Данные пользователя будут получены из базы данных с помощью Prisma Client.

      Начните с установки Express с помощью следующей команды:

      Поскольку вы используете TypeScript, вам также нужно будет установить соответствующие типы в качестве зависимостей разработки. Для этого запустите следующую команду:

      • npm install @types/express --save-dev

      После получения зависимостей вы можете перейти к настройке вашего приложения Express.

      Начните с открытия вашего главного исходного файла еще раз:

      Теперь удалите весь код в файле index.ts и замените его на следующий код для запуска вашего REST API:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      import express from 'express'
      
      const prisma = new PrismaClient()
      const app = express()
      
      app.use(express.json())
      
      // ... your REST API routes will go here
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Ниже приводится краткое описание элементов кода:

      1. Импорт PrismaClient и express из соответствующих пакетов npm.
      2. Создание объекта PrismaClient с помощью вызова конструктора и получения экземпляра с именем prisma.
      3. Создание вашего приложения Express с помощью вызова express().
      4. Добавление промежуточного слоя ПО с помощью вызова express.json() для обеспечения возможности корректной обработки данных в формате JSON с помощью Express.
      5. Запуск сервера на порту 3000.

      Теперь вы можете реализовать свой первый маршрут. Между вызовами app.use и app.listen добавьте следующий код:

      my-blog/src/index.ts

      . . .
      app.use(express.json())
      
      app.get('/users', async (req, res) => {
        const users = await prisma.user.findMany()
        res.json(users)
      })
      
      app.listen(3000, () =>
      console.log('REST API server ready at: http://localhost:3000'),
      )
      

      После добавления кода сохраните и закройте файл. Затем запустите локальный веб-сервер с помощью следующей команды:

      Результат будет выглядеть следующим образом:

      Output

      REST API server ready at: http://localhost:3000

      Чтобы получить доступ к маршруту /users, вы можете указать в адресной строке браузера http://localhost:3000/users или воспользоваться любым другим клиентом HTTP.

      В этом руководстве мы будем тестировать все маршруты REST API с помощью curl, HTTP клиента для командной строки.

      Примечание: если вы предпочитаете использовать клиент HTTP с графическим пользовательским интерфейсом, вы можете использовать такие альтернативные варианты, как Postwoman или Advanced REST Client.

      Чтобы протестировать маршрут, откройте новое окно терминала или вкладку (чтобы ваш локальный веб-сервер мог продолжать работу) и выполните следующую команду:

      • curl http://localhost:3000/users

      Вы получите данные сущности User, которую вы создали в предыдущем шаге:

      Output

      [{"id":1,"email":"alice@prisma.io","name":"Alice"}]

      Обратите внимание, что в этот раз массив posts не включен в результат. Это происходит потому, что вы не передаете опцию include в вызов findMany при реализации маршрута /users.

      Вы успешно реализовали свой первый маршрут REST API в /users. В следующем шаге вы будете реализовывать оставшиеся маршруты REST API, чтобы добавить дополнительный функционал для вашего API.

      Шаг 6 — Реализация остальных маршрутов REST API

      В этом шаге вы будете реализовывать оставшиеся маршруты REST API для вашего приложения для ведения блога. В результате ваш веб-сервер будет обслуживать различные запросы типа GET, POST, PUT и DELETE.

      Ниже приводится описание различных маршрутов, которые вы будете реализовывать:

      Метод HTTP Маршрут Описание
      GET /feed Получает все опубликованные посты.
      GET /post/:id Получает определенный пост по его идентификатору.
      POST /user Создает нового пользователя.
      POST /post Создает новый пост (в виде черновика).
      PUT /post/publish/:id Задает для поля published поста значение true.
      DELETE post/:id Удаляет пост по его идентификатору.

      Теперь вы можете перейти к реализации остальных маршрутов GET.

      Откройте файл index.ts с помощью следующей команды:

      Затем добавьте следующий код под реализацией маршрута /users:

      my-blog/src/index.ts

      . . .
      
      app.get('/feed', async (req, res) => {
        const posts = await prisma.post.findMany({
          where: { published: true },
          include: { author: true }
        })
        res.json(posts)
      })
      
      app.get(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.findOne({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Сохраните и закройте файл.

      Этот код реализует маршруты API для двух запросов GET:

      • /feed: возвращает список опубликованных постов.
      • /post/:id: возвращает конкретный пост по его идентификатору.

      Prisma Client используется в обеих реализациях. В реализации маршрута /feed запрос, который вы отправляете с помощью Prisma Client, отфильтровывает все записи Post, где в колонке published указано значение true. Кроме того, запрос Prisma Client использует опцию include для получения связанной информации об авторе для каждого возвращаемого поста. В реализации маршрута /post/:id вы передаете идентификатор, который будет получен из URL-адреса, для чтения конкретной записи Post из базы данных.

      Вы можете остановить работу сервера, нажав CTRL+C на клавиатуре. Затем перезапустите его с помощью следующей команды:

      Чтобы протестировать маршрут /feed, вы можете воспользоваться следующей командой curl:

      • curl http://localhost:3000/feed

      Поскольку ни один пост еще не был опубликован, ответ будет содержать пустой массив:

      Output

      []

      Чтобы протестировать маршрут /post/:id, вы можете воспользоваться следующей командой curl:

      • curl http://localhost:3000/post/1

      Она вернет пост, созданный вами ранее:

      Output

      {"id":1,"title":"Hello World","content":null,"published":false,"authorId":1}

      Далее реализуйте два маршрута POST. Добавьте следующий код в файл index.ts под реализацией трех маршрутов GET:

      my-blog/src/index.ts

      . . .
      
      app.post(`/user`, async (req, res) => {
        const result = await prisma.user.create({
          data: { ...req.body },
        })
        res.json(result)
      })
      
      app.post(`/post`, async (req, res) => {
        const { title, content, authorEmail } = req.body
        const result = await prisma.post.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { email: authorEmail } },
          },
        })
        res.json(result)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      После этого сохраните и закройте файл.

      Этот код реализует маршруты API для двух запросов POST:

      • /user: создает нового пользователя в базе данных.
      • /post: создает новый пост в базе данных.

      Как и ранее, Prisma Client используется в обеих реализациях. В реализации маршрута /user вы передаете значения из тела запроса HTTP в запрос create Prisma Client.

      Маршрут /post имеет немного более сложную структуру: здесь вы не можете прямо передавать значения из тела HTTP запроса, вместо этого вам сначала нужно вручную извлечь их, а уже после этого передать эти полученные значения в запрос Prisma Client. Это вызвано тем, что структура JSON в теле запроса не соответствует структуре, которую ожидает Prisma Client, поэтому вам нужно вручную создать ожидаемую структуру.

      Вы можете протестировать новые маршруты, остановив сервер с помощью CTRL+C. Затем перезапустите его с помощью следующей команды:

      Чтобы создать нового пользователя с помощью маршрута /user, вы можете отправить следующий POST запрос с помощью curl:

      • curl -X POST -H "Content-Type: application/json" -d '{"name":"Bob", "email":"bob@prisma.io"}' http://localhost:3000/user

      В результате в базе данных будет создан новый пользователь, а в консоли будет отображен следующий вывод:

      Output

      {"id":2,"email":"bob@prisma.io","name":"Bob"}

      Чтобы создать новый пост с помощью маршрута /post, вы можете отправить следующий POST запрос с помощью curl:

      • curl -X POST -H "Content-Type: application/json" -d '{"title":"I am Bob", "authorEmail":"bob@prisma.io"}' http://localhost:3000/post

      В результате в базе данных будет создан новый пост, который будет привязан к пользователю с электронной почтой bob@prisma.io. В консоль будет выведен следующий текст:

      Output

      {"id":2,"title":"I am Bob","content":null,"published":false,"authorId":2}

      В заключение вы можете реализовать маршруты PUT и DELETE.

      Откройте файл index.ts с помощью следующей команды:

      Затем под реализацией двух маршрутов POST добавьте выделенный код:

      my-blog/src/index.ts

      . . .
      
      app.put('/post/publish/:id', async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.update({
          where: { id: Number(id) },
          data: { published: true },
        })
        res.json(post)
      })
      
      app.delete(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.delete({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Сохраните и закройте файл.

      Этот код реализует маршруты API для одного запроса PUT и одного запроса DELETE:

      • /post/publish/:id (PUT): публикует пост по его идентификатору.
      • /post/:id(DELETE): удаляет пост по его идентификатору.

      Prisma Client снова используется в обеих реализациях. В реализации маршрута /post/publish/:id идентификатор поста, который будет опубликован, извлекается из URL-адреса и передается в запрос update Prisma Client. Реализация маршрута /post/:id, который будет удалять пост в базе данных, также извлекает идентификатор поста из URL-адреса и передает его в запрос delete Prisma Client.

      Еще раз остановите сервер, нажав CTRL+C на клавиатуре. Затем перезапустите его с помощью следующей команды:

      Вы можете протестировать маршрут PUT с помощью следующей команды curl:

      • curl -X PUT http://localhost:3000/post/publish/2

      В этом случае пост будет опубликован с идентификатором, равным 2. Если вы повторно отправите запрос для маршрута /feed, этот пост будет добавлен в ответ.

      Далее вы можете протестировать маршрут DELETE с помощью следующей команды curl:

      • curl -X DELETE http://localhost:3000/post/1

      В результате выполнения этой команды будет удален пост с идентификатором 1. Чтобы убедиться, что пост с этим идентификатором был удален, повторно отправьте запрос GET для маршрута /post/1.

      В этом шаге вы реализовали оставшиеся маршруты REST API для вашего приложения для ведения блога. API теперь отвечает на различные запросы GET, POST, PUT и DELETE и реализует функционал для чтения и записи данных в базе данных.

      Заключение

      С помощью этой статьи вы создали сервер REST API с рядом различных маршрутов для создания, чтения, обновления и удаления данных пользователя и поста для примера приложения для ведения блога. Внутри маршрутов API вы используете Prisma Client для отправки соответствующих запросов для вашей базы данных.

      В качестве следующих шагов вы можете реализовать дополнительные маршруты API или расширить схему вашей базы данных с помощью Prisma Migrate. Обязательно ознакомьтесь с документацией Prisma для получения информации о различных аспектах Prisma и изучите ряд готовых проектов в репозитории prisma-examples, воспользовавшись такими инструментами, как GraphQL или grPC API.



      Source link

      Erstellen einer REST-API mit Prisma und PostgreSQL


      Der Autor hat den Diversity in Tech Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      Einführung

      Prisma ist ein Open-Source-basiertes Datenbank-Toolkit. Es besteht aus drei Haupttools:

      • Prisma Client: Ein automatisch generierter und typensicherer Query Builder für Node.js und TypeScript.
      • Prisma Migrate: Ein deklaratives Modellierungs- und Migrationssystem für Daten.
      • Prisma Studio: Eine GUI zum Anzeigen und Bearbeiten von Daten in Ihrer Datenbank.

      Diese Tools dienen dazu, die Produktivität von Anwendungsentwicklern in ihren Datenbank-Workflows zu steigern. Einer der größten Vorteile von Prisma ist die Ebene der Abstraktion, die möglich ist: Anstatt komplexe SQL-Abfragen oder Schemamigrationen zu erstellen, können Anwendungsentwickler bei der Arbeit mit ihrer Datenbank unter Verwendung von Prisma Daten intuitiver verwalten.

      In diesem Tutorial erstellen Sie eine REST-API für eine kleine Blogging-Anwendung in TypeScript mithilfe von Prisma und eine PostgreSQL-Datenbank. Sie werden Ihre PostgreSQL-Datenbank mit Docker lokal einrichten und die REST-API mit Express implementieren. Am Ende des Tutorials verfügen Sie über einen Webserver, der auf Ihrem Rechner lokal ausgeführt wird und auf verschiedene HTTP-Anfragen reagieren sowie Daten in der Datenbank lesen und schreiben kann.

      Voraussetzungen

      Dieses Tutorial setzt Folgendes voraus:

      Grundlegende Vertrautheit mit TypeScript und REST-APIs ist hilfreich, für dieses Tutorial jedoch nicht erforderlich.

      Schritt 1 — Erstellen Ihres TypeScript-Projekts

      In diesem Schritt werden Sie mit npm ein einfaches TypeScript-Projekt einrichten. Dieses Projekt wird als Grundlage für die REST-API dienen, die Sie im Laufe dieses Tutorials erstellen werden.

      Erstellen Sie zunächst ein neues Verzeichnis für Ihr Projekt:

      Navigieren Sie als Nächstes in das Verzeichnis und initialisieren Sie ein leeres npm-Projekt. Beachten Sie, dass die Option -y hier bedeutet, dass Sie die interaktiven Eingabeaufforderungen des Befehls überspringen. Um die Eingabeaufforderungen zu durchlaufen, entfernen Sie -y aus dem Befehl:

      Weitere Details zu diesen Eingabeaufforderungen finden Sie in Schritt 1 unter Verwenden von Node.js-Modulen mit npm und package.json.

      Sie erhalten eine Ausgabe, die der folgenden ähnelt und die Standardantworten umfasst:

      Output

      Wrote to /.../my-blog/package.json: { "name": "my-blog", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      Dieser Befehl erstellt eine minimale package.json-Datei, die Sie als Konfigurationsdatei für Ihr npm-Projekt verwenden können. Sie sind nun bereit, TypeScript in Ihrem Projekt zu konfigurieren.

      Führen Sie den folgenden Befehl für eine einfache TypeScript-Einrichtung aus:

      • npm install typescript ts-node @types/node --save-dev

      Dadurch werden drei Pakete als Entwicklungsabhängigkeiten in Ihrem Projekt installiert:

      • typescript: Die TypeScript-Toolchain.
      • ts-node: Ein Paket zum Ausführen von TypeScript-Anwendungen ohne vorherige Kompilierung in JavaScript.
      • @types/node: Die TypeScript-Typdefinitionen für Node.js.

      Die letzte Aufgabe besteht darin, eine tsconfig.json-Datei hinzuzufügen, um sicherzustellen, dass TypeScript für die von Ihnen erstellte Anwendung richtig konfiguriert ist.

      Führen Sie den folgenden Befehl aus, um die Datei zu erstellen:

      Fügen Sie in der Datei den folgenden JSON-Code hinzu:

      my-blog/tsconfig.json

      {
        "compilerOptions": {
          "sourceMap": true,
          "outDir": "dist",
          "strict": true,
          "lib": ["esnext"],
          "esModuleInterop": true
        }
      }
      

      Speichern und schließen Sie die Datei.

      Dies ist eine Standard- und Minimalkonfiguration für ein TypeScript-Projekt. Wenn Sie mehr über die einzelnen Eigenschaften der Konfigurationsdatei erfahren möchten, können Sie die TypeScript-Dokumentation konsultieren.

      Sie haben Ihr einfaches TypeScript-Projekt mit npm eingerichtet. Als Nächstes werden Sie Ihre PostgreSQL-Datenbank mit Docker einrichten und Prisma damit verbinden.

      Schritt 2 — Einrichten von Prisma mit PostgreSQL

      In diesem Schritt installieren Sie die Prisma-CLI , erstellen Ihre erste Prisma-Schemadatei, richten PostgreSQL mit Docker ein und verbinden Prisma damit. Das Prisma-Schema ist die wichtigste Konfigurationsdatei für Ihr Prisma-Setup und enthält das Datenbankschema.

      Installieren Sie zunächst die Prisma-CLI mit dem folgenden Befehl:

      • npm install @prisma/cli --save-dev

      Als bewährte Praxis wird empfohlen, die Prisma-CLI in Ihrem Projekt lokal zu installieren (und nicht im Rahmen einer globalen Installation). Dadurch lassen sich Versionskonflikte vermeiden, falls Sie mehr als ein Prisma-Projekt auf Ihrem Rechner verwenden.

      Als Nächstes richten Sie mit Docker Ihre PostgreSQL-Datenbank ein. Erstellen Sie mit dem folgenden Befehl eine neue Docker Compose-Datei:

      Fügen Sie der neu erstellten Datei den folgenden Code hinzu:

      my-blog/docker-compose.yml

      version: '3.8'
      services:
        postgres:
          image: postgres:10.3
          restart: always
          environment:
            - POSTGRES_USER=sammy
            - POSTGRES_PASSWORD=your_password
          volumes:
            - postgres:/var/lib/postgresql/data
          ports:
            - '5432:5432'
      volumes:
        postgres:
      

      Diese Docker Compose-Datei konfiguriert eine PostgreSQL-Datenbank, auf die über Port 5432 des Docker-Containers zugegriffen werden kann. Beachten Sie außerdem, dass die Anmeldedaten für die Datenbank aktuell sammy (Benutzer) und your_password (Passwort) lauten. Sie können diese Anmeldedaten in Ihren bevorzugten Benutzer und Ihr bevorzugtes Passwort ändern. Speichern und schließen Sie die Datei.

      Fahren Sie nun fort und starten Sie den PostgreSQL-Datenbankserver mit dem folgenden Befehl:

      Die Ausgabe dieses Befehls wird in etwa wie folgt aussehen:

      Output

      Pulling postgres (postgres:10.3)... 10.3: Pulling from library/postgres f2aa67a397c4: Pull complete 6de83ca23e55: Pull complete . . . Status: Downloaded newer image for postgres:10.3 Creating my-blog_postgres_1 ... done

      Sie können mit folgendem Befehl überprüfen, ob der Datenbankserver ausgeführt wird:

      Dadurch erhalten Sie eine Aufgabe, die in etwa wie folgt aussieht:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8547f8e007ba postgres:10.3 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp my-blog_postgres_1

      Nachdem der Datenbankserver ausgeführt wird, können Sie nun Ihr Prisma-Setup erstellen. Führen Sie den folgenden Befehl über die Prisma-CLI aus:

      Dadurch erhalten Sie folgende Ausgabe:

      Output

      ✔ Your Prisma schema was created at prisma/schema.prisma. You can now open it in your favorite editor.

      Beachten Sie, dass Sie als bewährte Praxis allen Aufrufen der Prisma-CLI npx voranstellen sollten. Dadurch wird sichergestellt, dass Sie Ihre lokale Installation verwenden.

      Nachdem Sie den Befehl ausgeführt haben, erstellt die Prisma-CLI in Ihrem Projekt einen neuen Ordner namens prisma. Er enthält die folgenden zwei Dateien:

      • schema.prisma: Die Hauptkonfigurationsdatei für Ihr Prisma-Projekt (schließt Ihr Datenmodell mit ein).
      • .env: Eine dotenv-Datei zum Definieren Ihrer Datenbankverbindungs-URL.

      Um sicherzustellen, dass Prisma den Speicherort Ihrer Datenbank kennt, öffnen Sie die Datei .env und passen Sie die Umgebungsvariable DATABASE_URL an.

      Öffnen Sie zunächst die .env-Datei:

      Jetzt können Sie die Umgebungsvariable wie folgt setzen:

      my-blog/prisma/.env

      DATABASE_URL="postgresql://sammy:your_password@localhost:5432/my-blog?schema=public"
      

      Ändern Sie die Anmeldedaten für die Datenbank unbedingt auf jene, die Sie in der Docker Compose-Datei angegeben haben. Um mehr über das Format der Verbindungs-URL zu erfahren, besuchen Sie die Prisma-Dokumentation.

      Wenn Sie damit fertig sind, speichern und schließen Sie die Datei.

      In diesem Schritt haben Sie Ihre PostgreSQL-Datenbank mit Docker eingerichtet, die Prisma-CLI installiert und Prisma über eine Umgebungsvariable mit der Datenbank verbunden. Im nächsten Abschnitt definieren Sie Ihr Datenmodell und erstellen Ihre Datenbanktabellen.

      Schritt 3 — Definieren des Datenmodells und Erstellen von Datenbanktabellen

      In diesem Schritt definieren Sie Ihr Datenmodell in der Prisma-Schemadatei. Dieses Datenmodell wird dann mit Prisma Migrate der Datenbank zugeordnet; dadurch werden die SQL-Anweisungen generiert und gesendet, um die Tabellen zu erstellen, die Ihrem Datenmodell entsprechen. Da Sie eine Blogging-Anwendung erstellen, werden die wichtigsten Entitäten der Anwendung Benutzer und Beiträge sein.

      Prisma verwendet seine eigene Datenmodellierungssprache zum Definieren der Form Ihrer Anwendungsdaten.

      Öffnen Sie zunächst Ihre schema.prisma-Datei mit dem folgenden Befehl:

      • nano prisma/schema.prisma

      Fügen Sie nun folgende Modelldefinitionen hinzu. Sie können die Modelle am Ende der Datei platzieren, unmittelbar nach dem generator client-Block:

      my-blog/prisma/schema.prisma

      . . .
      model User {
        id    Int     @default(autoincrement()) @id
        email String  @unique
        name  String?
        posts Post[]
      }
      
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
        author    User?   @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-de)
        authorId  Int?
      }
      

      Speichern und schließen Sie die Datei.

      Sie definieren zwei Modelle namens User und Post. Jedes von ihnen verfügt über eine Reihe vonFeldern, die die Eigenschaften des Modells darstellen. Die Modelle werden Datenbanktabellen zugeordnet; die Felder stellen die einzelnen Spalten dar.

      Beachten Sie außerdem, dass es eine one-to-many-Beziehung zwischen den beiden Modellen gibt, die von den Beziehungsfeldern posts und author in User und Post angegeben werden. Das bedeutet, dass ein Benutzer mit verschiedenen Beiträgen verknüpft sein kann.

      Nach Implementierung dieser Modelle können Sie nun unter Verwendung von Prisma Migrate die entsprechenden Tabellen in der Datenbank erstellen. Führen Sie in Ihrem Terminal folgenden Befehl aus:

      • npx prisma migrate save --experimental --create-db --name "init"

      Dieser Befehl erstellt in Ihrem Dateisystem eine neue Migration. Hier finden Sie einen kurzen Überblick über die drei Optionen, die dem Befehl bereitgestellt werden:

      • --experimental: Erforderlich, da Prisma Migrate derzeit in einem experimentellen Zustand ist.
      • --create-db: Ermöglicht Prisma Migrate die Erstellung der Datenbank mit dem Namen my-blog, die in der Verbindungs-URL angegeben ist.
      • --name "init": Gibt den Namen der Migration an (wird zum Benennen des Migrationsordners verwendet, der in Ihrem Dateisystem erstellt wird).

      Die Ausgabe dieses Befehls wird in etwa wie folgt aussehen:

      Output

      New datamodel: // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @default(autoincrement()) @id email String @unique name String? posts Post[] } model Post { id Int @default(autoincrement()) @id title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql-de) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      Sie können die Migrationsdateien erkunden, die im Verzeichnis prisma/migrations erstellt wurden.

      Um die Migration für Ihre Datenbank auszuführen und die Tabellen für Ihre Prisma-Modelle zu erstellen, führen Sie in Ihrem Terminal folgenden Befehl aus:

      • npx prisma migrate up --experimental

      Sie erhalten die folgende Ausgabe:

      Output

      . . . Checking the datasource for potential data loss... Database Changes: Migration Database actions Status 20200811140708-init 2 CreateTable statements. Done 🚀 You can get the detailed db changes with prisma migrate up --experimental --verbose Or read about them here: ./migrations/20200811140708-init/README.md 🚀 Done with 1 migration in 206ms.

      Prisma Migrate generiert nun die SQL-Anweisungen, die für die Migration erforderlich sind, und sendet sie an die Datenbank. Im Folgenden sehen Sie die SQL-Anweisungen, die die Tabellen erstellt haben:

      CREATE TABLE "public"."User" (
        "id" SERIAL,
        "email" text  NOT NULL ,
        "name" text   ,
        PRIMARY KEY ("id")
      )
      
      CREATE TABLE "public"."Post" (
        "id" SERIAL,
        "title" text  NOT NULL ,
        "content" text   ,
        "published" boolean  NOT NULL DEFAULT false,
        "authorId" integer   ,
        PRIMARY KEY ("id")
      )
      
      CREATE UNIQUE INDEX "User.email" ON "public"."User"("email")
      
      ALTER TABLE "public"."Post" ADD FOREIGN KEY ("authorId")REFERENCES "public"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE
      

      In diesem Schritt haben Sie mit Prisma Migrate Ihr Datenmodell im Prisma-Schema definiert und die jeweiligen Datenbanktabellen erstellt. Im nächsten Schritt installieren Sie Prisma Client in Ihrem Projekt, damit Sie die Datenbank abfragen können.

      Schritt 4 — Erkunden von Prisma Client-Abfragen in einem einfachen Skript

      Prisma Client ist ein automatisch generierter und typensicherer Query Builder, mit dem Sie aus einer Node.js- oder TypeScript-Anwendung Daten in einer Datenbank programmatisch lesen und schreiben können. Sie werden ihn für Datenbankzugriff in Ihren REST-API-Routen verwenden, indem Sie traditionelle ORMs, einfache SQL-Abfragen, benutzerdefinierte Datenzugriffsebenen oder andere Methoden zur Kommunikation mit einer Datenbank ersetzen.

      In diesem Schritt installieren Sie Prisma Client und lernen die Abfragen kennen, die Sie damit senden können. Bevor Sie in den nächsten Schritten die Routen für Ihre REST-API implementieren, werden Sie zunächst einige der Prisma Client-Abfragen in einem einfachen ausführbaren Skript erkunden.

      Zuerst installieren Sie Prisma Client in Ihrem Projekt, indem Sie Ihr Terminal öffnen und das Prisma Client npm-Paket installieren:

      • npm install @prisma/client

      Erstellen Sie als Nächstes ein neues Verzeichnis namens src, das Ihre Quelldateien enthalten wird:

      Erstellen Sie nun in dem neuen Verzeichnis eine TypeScript-Datei:

      Alle Prisma Client-Abfragen geben promises (Zusagen) zurück, auf die Sie in Ihrem Code warten können. Dazu müssen Sie die Abfragen in einer async-Funktion senden.

      Fügen Sie den folgenden Codebaustein mit einer async-Funktion hinzu, die in Ihrem Skript ausgeführt wird:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        // ... your Prisma Client queries will go here
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      Hier finden Sie einen kurzen Überblick über den Codebaustein:

      1. Sie importieren den PrismaClient-Konstruktor aus dem zuvor installierten @prisma/client npm-Paket.
      2. Sie instanziieren PrismaClient, indem Sie den Konstrukteur aufrufen, und erhalten eine Instanz namens prisma.
      3. Sie definieren eine async-Funktion namens main, wo Sie als Nächstes Ihre Prisma Client-Abfragen hinzufügen werden.
      4. Sie rufen die main-Funktion auf, fangen dabei alle möglichen Ausnahmen ab und stellen sicher, dass Prisma Client alle offenen Datenbankverbindungen schließt, indem Sie prisma.disconnect() aufrufen.

      Nach Implementierung der main-Funktion können Sie mit dem Hinzufügen von Prisma Client-Abfragen in das Skript beginnen. Passen Sie index.ts wie folgt an:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        const newUser = await prisma.user.create({
          data: {
            name: 'Alice',
            email: 'alice@prisma.io',
            posts: {
              create: {
                title: 'Hello World',
              },
            },
          },
        })
        console.log('Created new user: ', newUser)
      
        const allUsers = await prisma.user.findMany({
          include: { posts: true },
        })
        console.log('All users: ')
        console.dir(allUsers, { depth: null })
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      In diesem Code verwenden Sie zwei Prisma Client-Abfragen:

      • create: Erstellt einen neuen User-Eintrag. Beachten Sie, dass Sie in Wahrheit ein nested write verwenden, was bedeutet, dass Sie in derselben Abfrage sowohl einen User– als auch einen Post-Eintrag erstellen.
      • findMany: Liest alle vorhandenen User-Einträge aus der Datenbank. Sie geben die include-Option an, wodurch zusätzlich auch die entsprechenden Post-Einträge für die einzelnen User-Einträge geladen werden.

      Führen Sie das Skript nun mit dem folgenden Befehl aus:

      Sie erhalten in Ihrem Terminal folgende Ausgabe:

      Output

      Created new user: { id: 1, email: 'alice@prisma.io', name: 'Alice' } [ { id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [ { id: 1, title: 'Hello World', content: null, published: false, authorId: 1 } ] }

      Anmerkung: Wenn Sie eine Datenbank-GUI verwenden, können Sie überprüfen, ob die Daten erstellt wurden, indem Sie sich die Tabellen User und Post ansehen. Alternativ können Sie die Daten in Prisma Studio erkunden, indem Sie npx prisma studio --experimental ausführen.

      Sie haben Prisma Client nun verwendet, um Daten in Ihrer Datenbank zu lesen und zu schreiben. In den verbleibenden Schritten wenden Sie dieses neue Wissen an, um die Routen für eine beispielhafte REST-API zu implementieren.

      Schritt 5 — Implementieren Ihrer ersten REST-API-Route

      In diesem Schritt installieren Sie Express in Ihrer Anwendung. Express ist ein beliebtes Webframework für Node.js, das Sie zur Implementierung der REST-API-Routen in diesem Projekt verwenden werden. Die erste Route, die Sie implementieren werden, erlaubt es, mithilfe einer GET-Anfrage alle Benutzer von der API abzurufen. Die Benutzerdaten werden mit Prisma Client aus der Datenbank abgerufen.

      Installieren Sie dann Express mit dem folgenden Befehl:

      Da Sie TypeScript verwenden, sollten Sie die jeweiligen Typen auch als Entwicklungsabhängigkeiten installieren. Führen Sie dazu folgenden Befehl aus:

      • npm install @types/express --save-dev

      Nach Implementierung der Abhängigkeiten können Sie Ihre Express-Anwendung einrichten.

      Öffnen Sie dazu erneut Ihre zentrale Quelldatei:

      Löschen Sie nun den ganzen Code in index.ts und ersetzen Sie ihn durch Folgendes, um Ihre REST-API zu starten:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      import express from 'express'
      
      const prisma = new PrismaClient()
      const app = express()
      
      app.use(express.json())
      
      // ... your REST API routes will go here
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Hier finden Sie eine kurze Aufschlüsselung des Codes:

      1. Sie importieren PrismaClient und express aus den jeweiligen npm-Paketen.
      2. Sie instanziieren PrismaClient, indem Sie den Konstruktor aufrufen, und erhalten eine Instanz namens prisma.
      3. Sie erstellen Ihre Express-Anwendung, indem Sie express() aufrufen.
      4. Sie fügen die Middleware express.json() hinzu, um sicherzustellen, dass Express JSON-Daten ordnungsgemäß verarbeiten kann.
      5. Sie starten den Server unter Port 3000.

      Jetzt können Sie Ihre erste Route implementieren. Fügen Sie zwischen den Aufrufen für app.use und app.listen folgenden Code hinzu:

      my-blog/src/index.ts

      . . .
      app.use(express.json())
      
      app.get('/users', async (req, res) => {
        const users = await prisma.user.findMany()
        res.json(users)
      })
      
      app.listen(3000, () =>
      console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie anschließend Ihre Datei. Starten Sie dann mit dem folgenden Befehl Ihren lokalen Webserver:

      Sie erhalten die folgende Ausgabe:

      Output

      REST API server ready at: http://localhost:3000

      Um auf die Route /users zuzugreifen, können Sie Ihren Browser auf http://localhost:3000/users oder einen anderen HTTP-Client verweisen.

      In diesem Tutorial testen Sie alle REST-API-Routen mit curl (einem Terminal-basierten HTTP-Client).

      Anmerkung: Wenn Sie lieber einen GUI-basierten HTTP-Client verwenden, können Sie Alternativen wie Postwoman oder den Advanced REST Client verwenden.

      Öffnen Sie zum Testen Ihrer Route ein neues Terminalfenster oder eine Registerkarte (damit Ihr lokaler Webserver weiter ausgeführt werden kann) und führen Sie folgenden Befehl aus:

      • curl http://localhost:3000/users

      Sie erhalten die im vorherigen Schritt erstellten User-Daten:

      Output

      [{"id":1,"email":"alice@prisma.io","name":"Alice"}]

      Beachten Sie, dass das posts-Array diesmal nicht enthalten ist. Das liegt daran, dass Sie die Option include nicht an den findMany-Aufruf in der Implementierung der Route /users übergeben.

      Sie haben unter /users Ihre erste REST-API-Route implementiert. Im nächsten Schritt implementieren Sie die verbleibenden REST-API-Routen, um Ihrer API weitere Funktionen hinzuzufügen.

      Schritt 6 — Implementieren der verbleibenden REST-API-Routen

      In diesem Schritt implementieren Sie die verbleibenden REST-API-Routen für Ihre Blogging-Anwendung. Am Ende wird Ihr Webserver verschiedene GET-, POST-, PUT– und DELETE-Anfragen bereitstellen.

      Hier finden Sie einen Überblick über die verschiedenen Routen, die Sie implementieren werden:

      HTTP-Methode Route Beschreibung
      GET /feed Ruft alle veröffentlichten Beiträge ab.
      GET /post/:id Ruft einen einzelnen Beitrag anhand seiner ID ab.
      POST /user Erstellt einen neuen Benutzer.
      POST /post Erstellt einen neuen Beitrag (als Entwurf).
      PUT /post/publish/:id Setzt das published-Feld eines Beitrags auf true.
      DELETE post/:id Löscht einen Beitrag anhand seiner ID.

      Fahren Sie fort und implementieren Sie zunächst die verbleibenden GET-Routen.

      Öffnen Sie die Datei index.ts mit dem folgenden Befehl:

      Fügen Sie dann im Anschluss an die Implementierung der Route /users folgenden Code hinzu:

      my-blog/src/index.ts

      . . .
      
      app.get('/feed', async (req, res) => {
        const posts = await prisma.post.findMany({
          where: { published: true },
          include: { author: true }
        })
        res.json(posts)
      })
      
      app.get(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.findOne({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie Ihre Datei.

      Dieser Code implementiert die API-Routen für zwei GET-Anfragen:

      • /feed: Gibt eine Liste mit veröffentlichten Beiträgen zurück.
      • /post/:id: Gibt einen einzelnen Beitrag anhand seiner ID zurück.

      Prisma Client wird in beiden Implementierungen verwendet. In der Implementierung der Route /feed filtert die Abfrage, die Sie mit Prisma Client senden, nach allen Post-Einträgen, bei denen die Spalte published den Wert true enthält. Außerdem nutzt die Prisma Client-Abfrage include, um die entsprechenden author-Informationen für die einzelnen Beiträge abzurufen. In der Implementierung der Route /post/:id übergeben Sie die ID, die aus dem URL-Pfad abgerufen wird, um einen bestimmten Post-Eintrag aus der Datenbank zu lesen.

      Sie können den Server anhalten, indem Sie auf Ihrer Tastatur Strg+C drücken. Starten Sie dann den Server neu:

      Um die Route /feed zu testen, können Sie folgenden curl-Befehl verwenden:

      • curl http://localhost:3000/feed

      Da noch keine Beiträge veröffentlicht wurden, ist die Antwort ein leeres Array:

      Output

      []

      Um die Route /post/:id zu testen, können Sie folgenden curl-Befehl verwenden:

      • curl http://localhost:3000/post/1

      Dadurch wird der von Ihnen ursprünglich erstellte Beitrag zurückgegeben:

      Output

      {"id":1,"title":"Hello World","content":null,"published":false,"authorId":1}

      Implementieren Sie als Nächstes die beiden POST-Routen. Fügen Sie nach den Implementierungen der drei GET-Routen folgenden Code zu index.ts hinzu:

      my-blog/src/index.ts

      . . .
      
      app.post(`/user`, async (req, res) => {
        const result = await prisma.user.create({
          data: { ...req.body },
        })
        res.json(result)
      })
      
      app.post(`/post`, async (req, res) => {
        const { title, content, authorEmail } = req.body
        const result = await prisma.post.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { email: authorEmail } },
          },
        })
        res.json(result)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Wenn Sie damit fertig sind, speichern und schließen Sie die Datei.

      Dieser Code implementiert die API-Routen für zwei POST-Anfragen:

      • /user: Erstellt in der Datenbank einen neuen Benutzer.
      • /post: Erstellt in der Datenbank einen neuen Beitrag.

      Wie zuvor wird in beiden Implementierungen Prisma Client verwendet. In der Implementierung der Route /user übergeben Sie die Werte aus dem Haupttext der HTTP-Anfrage an die Prisma Client-Abfrage create.

      Die Route /post ist etwas aufwendiger: Hier können Sie die Werte aus dem Haupttext der HTTP-Anfrage nicht direkt übergeben; stattdessen müssen Sie sie zunächst manuell extrahieren, um sie dann an die Prisma Client-Abfrage zu übergeben. Der Grund dafür besteht darin, dass die Struktur von JSON im Haupttext der Anfrage nicht mit der Struktur übereinstimmt, die Prisma Client erwartet. Daher müssen Sie die erwartete Struktur manuell einrichten.

      Sie können die neuen Routen testen, indem Sie den Server mit Strg+C anhalten. Starten Sie dann den Server neu:

      Um über die Route /user einen neuen Benutzer zu erstellen, können Sie mit curl folgende POST-Anfrage senden:

      • curl -X POST -H "Content-Type: application/json" -d '{"name":"Bob", "email":"bob@prisma.io"}' http://localhost:3000/user

      Dadurch wird in der Datenbank ein neuer Benutzer erstellt und folgende Ausgabe ausgedruckt:

      Output

      {"id":2,"email":"bob@prisma.io","name":"Bob"}

      Um über die Route /post einen neuen Beitrag zu erstellen, können Sie mit curl folgende POST-Anfrage senden:

      • curl -X POST -H "Content-Type: application/json" -d '{"title":"I am Bob", "authorEmail":"bob@prisma.io"}' http://localhost:3000/post

      Dadurch wird in der Datenbank ein neuer Beitrag erstellt und unter Verwendung der E-Mail-Adresse bob@prisma.io mit dem Benutzer verbunden. Sie erhalten die folgende Ausgabe:

      Output

      {"id":2,"title":"I am Bob","content":null,"published":false,"authorId":2}

      Schließlich können Sie die Routen PUT und DELETE implementieren.

      Öffnen Sie die Datei index.ts mit dem folgenden Befehl:

      Fügen Sie dann nach der Implementierung der beiden POST-Routen den hervorgehobenen Code hinzu:

      my-blog/src/index.ts

      . . .
      
      app.put('/post/publish/:id', async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.update({
          where: { id: Number(id) },
          data: { published: true },
        })
        res.json(post)
      })
      
      app.delete(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.delete({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Speichern und schließen Sie Ihre Datei.

      Dieser Code implementiert die API-Routen für eine PUT– sowie eine DELETE-Anfrage.

      • /post/publish/:id (PUT): Veröffentlicht einen Beitrag anhand seiner ID.
      • /post/:id (DELETE) Löscht einen Beitrag anhand seiner ID.

      Erneut wird Prisma Client in beiden Implementierungen verwendet. In der Implementierung der Route /post/publish/:id wird die ID des zu veröffentlichenden Beitrags von der URL abgerufen und an die update-Abfrage von Prisma Client übergeben. Die Implementierung der Route /post/:id zum Löschen eines Beitrags in der Datenbank ruft außerdem die Beitrags-ID aus der URL ab und übergibt sie an die delete-Abfrage von Prisma Client.

      Halten Sie den Server mit Strg+C auf Ihrer Tastatur erneut an. Starten Sie dann den Server neu:

      Sie können die Route PUT mit dem folgenden curl-Befehl testen:

      • curl -X PUT http://localhost:3000/post/publish/2

      Dadurch wird der Beitrag mit einem ID-Wert von 2 veröffentlicht. Wenn Sie die Anfrage /feed neu senden, wird dieser Beitrag nun in die Antwort aufgenommen.

      Abschließend können Sie die Route DELETE mit dem folgenden curl-Befehl testen:

      • curl -X DELETE http://localhost:3000/post/1

      Dadurch wird der Beitrag mit dem ID-Wert von 1 gelöscht. Um zu überprüfen, ob der Beitrag mit dieser ID gelöscht wurde, können Sie erneut eine GET-Anfrage an die Route /post/1 senden.

      In diesem Schritt haben Sie die verbleibenden REST-API-Routen für Ihre Blogging-Anwendung implementiert. Die API reagiert nun auf verschiedene GET-, POST-, PUT– und DELETE-Anfragen und implementiert Funktionen zum Lesen und Schreiben von Daten in der Datenbank.

      Zusammenfassung

      In diesem Artikel haben Sie eine REST-API mit einer Reihe von verschiedenen Routen erstellt, um Benutzer- und Beitragsdaten für eine beispielhafte Blogging-Anwendung zu erstellen, zu lesen, zu aktualisieren und zu löschen. Innerhalb der API-Routen haben Sie den Prisma Client zum Senden der entsprechenden Abfragen an Ihre Datenbank verwendet.

      Als Nächstes können Sie weitere API-Routen implementieren oder Ihr Datenbankschema mithilfe von Prisma Migrate erweitern. Konsultieren Sie die Prisma-Dokumentation, um mehr über verschiedene Aspekte von Prisma zu erfahren und einige sofort einsatzbereite Beispielprojekte zu erkunden (im Repository prisma-examples). Verwenden Sie dazu Tools wie GraphQL oder grPC APIs.



      Source link

      How To Build a REST API with Prisma and PostgreSQL


      The author selected the Diversity in Tech Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      Prisma is an open source database toolkit. It consists of three main tools:

      • Prisma Client: An auto-generated and type-safe query builder for Node.js and TypeScript.
      • Prisma Migrate: A declarative data modeling and migration system.
      • Prisma Studio: A GUI to view and edit data in your database.

      These tools aim to increase an application developer’s productivity in their database workflows. One of the top benefits of Prisma is the level of abstraction it provides: Instead of figuring out complex SQL queries or schema migrations, application developers can reason about their data in a more intuitive way when using Prisma to work with their database.

      In this tutorial, you will build a REST API for a small blogging application in TypeScript using Prisma and a PostgreSQL database. You will set up your PostgreSQL database locally with Docker and implement the REST API routes using Express. At the end of the tutorial, you will have a web server running locally on your machine that can respond to various HTTP requests and read and write data in the database.

      Prerequisites

      This tutorial assumes the following:

      Basic familiarity with TypeScript and REST APIs is helpful but not required for this tutorial.

      Step 1 — Creating Your TypeScript Project

      In this step, you will set up a plain TypeScript project using npm. This project will be the foundation for the REST API you’re going to build throughout the course of this tutorial.

      First, create a new directory for your project:

      Next, navigate into the directory and initialize an empty npm project. Note that the -y option here means that you’re skipping the interactive prompts of the command. To run through the prompts, remove -y from the command:

      For more details on these prompts, you can follow Step 1 in How To Use Node.js Modules with npm and package.json.

      You’ll receive output similar to the following with the default responses in place:

      Output

      Wrote to /.../my-blog/package.json: { "name": "my-blog", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }

      This command creates a minimal package.json file that you use as the configuration file for your npm project. You’re now ready to configure TypeScript in your project.

      Execute the following command for a plain TypeScript setup:

      • npm install typescript ts-node @types/node --save-dev

      This installs three packages as development dependencies in your project:

      • typescript: The TypeScript toolchain.
      • ts-node: A package to run TypeScript applications without prior compilation to JavaScript.
      • @types/node: The TypeScript type definitions for Node.js.

      The last thing to do is to add a tsconfig.json file to ensure TypeScript is properly configured for the application you’re going to build.

      First, run the following command to create the file:

      Add the following JSON code into the file:

      my-blog/tsconfig.json

      {
        "compilerOptions": {
          "sourceMap": true,
          "outDir": "dist",
          "strict": true,
          "lib": ["esnext"],
          "esModuleInterop": true
        }
      }
      

      Save and exit the file.

      This is a standard and minimal configuration for a TypeScript project. If you want to learn about the individual properties of the configuration file, you can look them up in the TypeScript documentation.

      You’ve set up your plain TypeScript project using npm. Next you’ll set up your PostgreSQL database with Docker and connect Prisma to it.

      Step 2 — Setting Up Prisma with PostgreSQL

      In this step, you will install the Prisma CLI, create your initial Prisma schema file, and set up PostgreSQL with Docker and connect Prisma to it. The Prisma schema is the main configuration file for your Prisma setup and contains your database schema.

      Start by installing the Prisma CLI with the following command:

      • npm install @prisma/cli --save-dev

      As a best practice, it is recommended to install the Prisma CLI locally in your project (as opposed to a global installation). This helps avoid version conflicts in case you have more than one Prisma project on your machine.

      Next, you’ll set up your PostgreSQL database using Docker. Create a new Docker Compose file with the following command:

      Now add the following code to the newly created file:

      my-blog/docker-compose.yml

      version: '3.8'
      services:
        postgres:
          image: postgres:10.3
          restart: always
          environment:
            - POSTGRES_USER=sammy
            - POSTGRES_PASSWORD=your_password
          volumes:
            - postgres:/var/lib/postgresql/data
          ports:
            - '5432:5432'
      volumes:
        postgres:
      

      This Docker Compose file configures a PostgreSQL database that can be accessed via port 5432 of the Docker container. Also note that the database credentials are currently set as sammy (user) and your_password (password). Feel free to adjust these credentials to your preferred user and password. Save and exit the file.

      With this setup in place, go ahead and launch the PostgreSQL database server with the following command:

      The output of this command will be similar to this:

      Output

      Pulling postgres (postgres:10.3)... 10.3: Pulling from library/postgres f2aa67a397c4: Pull complete 6de83ca23e55: Pull complete . . . Status: Downloaded newer image for postgres:10.3 Creating my-blog_postgres_1 ... done

      You can verify that the database server is running with the following command:

      This will output something similar to this:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8547f8e007ba postgres:10.3 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp my-blog_postgres_1

      With the database server running, you can now create your Prisma setup. Run the following command from the Prisma CLI:

      This will print the following output:

      Output

      ✔ Your Prisma schema was created at prisma/schema.prisma. You can now open it in your favorite editor.

      Note that as a best practice, you should prefix all invocations of the Prisma CLI with npx. This ensures your local installation is being used.

      After you ran the command, the Prisma CLI created a new folder called prisma in your project. It contains the following two files:

      • schema.prisma: The main configuration file for your Prisma project (will include your data model).
      • .env: A dotenv file to define your database connection URL.

      To make sure Prisma knows about the location of your database, open the .env file and adjust the DATABASE_URL environment variable.

      First open the .env file:

      Now you can set the environment variable as follows:

      my-blog/prisma/.env

      DATABASE_URL="postgresql://sammy:your_password@localhost:5432/my-blog?schema=public"
      

      Make sure to change the database credentials to the ones you specified in the Docker Compose file. To learn more about the format of the connection URL, visit the Prisma docs.

      Once you’re done, save and exit the file.

      In this step, you set up your PostgreSQL database with Docker, installed the Prisma CLI, and connected Prisma to the database via an environment variable. In the next section, you’ll define your data model and create your database tables.

      Step 3 — Defining Your Data Model and Creating Database Tables

      In this step, you will define your data model in the Prisma schema file. This data model will then be mapped to the database with Prisma Migrate, which will generate and send the SQL statements for creating the tables that correspond to your data model. Since you’re building a blogging application, the main entities of the application will be users and posts.

      Prisma uses its own data modeling language to define the shape of your application data.

      First, open your schema.prisma file with the following command:

      • nano prisma/schema.prisma

      Now, add the following model definitions to it. You can place the models at the bottom of the file, right after the generator client block:

      my-blog/prisma/schema.prisma

      . . .
      model User {
        id    Int     @default(autoincrement()) @id
        email String  @unique
        name  String?
        posts Post[]
      }
      
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
        author    User?   @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql)
        authorId  Int?
      }
      

      Save and exit the file.

      You are defining two models, called User and Post. Each of these has a number of fields that represent the properties of the model. The models will be mapped to database tables; the fields represent the individual columns.

      Also note that there’s a one-to-many relation between the two models, specified by the posts and author relation fields on User and Post. This means that one user can be associated with many posts.

      With these models in place, you can now create the corresponding tables in the database using Prisma Migrate. In your terminal run the following command:

      • npx prisma migrate save --experimental --create-db --name "init"

      This command creates a new migration on your filesystem. Here’s a quick overview of the three options that are provided to the command:

      • --experimental: Required because Prisma Migrate is currently in an experimental state.
      • --create-db: Enables Prisma Migrate to create the database named my-blog that’s specified in the connection URL.
      • --name "init": Specifies the name of the migration (will be used to name the migration folder that’s created on your filesystem).

      The output of this command will be similar to this:

      Output

      New datamodel: // This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } model User { id Int @default(autoincrement()) @id email String @unique name String? posts Post[] } model Post { id Int @default(autoincrement()) @id title String content String? published Boolean @default(false) author User? @relation(fields: [authorId], references: tag:www.digitalocean.com,2005:/community/tutorials/how-to-build-a-rest-api-with-prisma-and-postgresql) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      Feel free to explore the migration files that have been created in the prisma/migrations directory.

      To run the migration against your database and create the tables for your Prisma models, run the following command in your terminal:

      • npx prisma migrate up --experimental

      You’ll receive the following output:

      Output

      . . . Checking the datasource for potential data loss... Database Changes: Migration Database actions Status 20200811140708-init 2 CreateTable statements. Done 🚀 You can get the detailed db changes with prisma migrate up --experimental --verbose Or read about them here: ./migrations/20200811140708-init/README.md 🚀 Done with 1 migration in 206ms.

      Prisma Migrate now generates the SQL statements that are required for the migration and sends them to the database. The following are the SQL statements that created the tables:

      CREATE TABLE "public"."User" (
        "id" SERIAL,
        "email" text  NOT NULL ,
        "name" text   ,
        PRIMARY KEY ("id")
      )
      
      CREATE TABLE "public"."Post" (
        "id" SERIAL,
        "title" text  NOT NULL ,
        "content" text   ,
        "published" boolean  NOT NULL DEFAULT false,
        "authorId" integer   ,
        PRIMARY KEY ("id")
      )
      
      CREATE UNIQUE INDEX "User.email" ON "public"."User"("email")
      
      ALTER TABLE "public"."Post" ADD FOREIGN KEY ("authorId")REFERENCES "public"."User"("id") ON DELETE SET NULL ON UPDATE CASCADE
      

      In this step, you defined your data model in your Prisma schema and created the respective databases tables with Prisma Migrate. In the next step, you’ll install Prisma Client in your project so that you can query the database.

      Step 4 — Exploring Prisma Client Queries in a Plain Script

      Prisma Client is an auto-generated and type-safe query builder that you can use to programmatically read and write data in a database from a Node.js or TypeScript application. You will use it for database access within your REST API routes, replacing traditional ORMs, plain SQL queries, custom data access layers, or any other method of talking to a database.

      In this step, you will install Prisma Client and get familiar with the queries you can send with it. Before implementing the routes for your REST API in the next steps, you will first explore some of the Prisma Client queries in a plain, executable script.

      First, go ahead and install Prisma Client in your project by opening up your terminal and installing the Prisma Client npm package:

      • npm install @prisma/client

      Next, create a new directory called src that will contain your source files:

      Now create a TypeScript file inside of the new directory:

      All of the Prisma Client queries return promises that you can await in your code. This requires you to send the queries inside of an async function.

      Add the following boilerplate with an async function that’s executed in your script:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        // ... your Prisma Client queries will go here
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      Here’s a quick breakdown of the boilerplate:

      1. You import the PrismaClient constructor from the previously installed @prisma/client npm package.
      2. You instantiate PrismaClient by calling the constructor and obtain an instance called prisma.
      3. You define an async function called main where you’ll add your Prisma Client queries next.
      4. You call the main function, while catching any potential exceptions and ensuring Prisma Client closes any open database connections by calling prisma.disconnect().

      With the main function in place, you can start adding Prisma Client queries to the script. Adjust index.ts to look as follows:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      
      const prisma = new PrismaClient()
      
      async function main() {
        const newUser = await prisma.user.create({
          data: {
            name: 'Alice',
            email: 'alice@prisma.io',
            posts: {
              create: {
                title: 'Hello World',
              },
            },
          },
        })
        console.log('Created new user: ', newUser)
      
        const allUsers = await prisma.user.findMany({
          include: { posts: true },
        })
        console.log('All users: ')
        console.dir(allUsers, { depth: null })
      }
      
      main()
        .catch((e) => console.error(e))
        .finally(async () => await prisma.disconnect())
      

      In this code, you’re using two Prisma Client queries:

      • create: Creates a new User record. Notice that you’re actually using a nested write, meaning you’re creating both a User and Post record in the same query.
      • findMany: Reads all existing User records from the database. You’re providing the include option that additionally loads the related Post records for each User record.

      Now run the script with the following command:

      You will receive the following output in your terminal:

      Output

      Created new user: { id: 1, email: 'alice@prisma.io', name: 'Alice' } [ { id: 1, email: 'alice@prisma.io', name: 'Alice', posts: [ { id: 1, title: 'Hello World', content: null, published: false, authorId: 1 } ] }

      Note: If you are using a database GUI you can validate that the data was created by looking at the User and Post tables. Alternatively, you can explore the data in Prisma Studio by running npx prisma studio --experimental.

      You’ve now used Prisma Client to read and write data in your database. In the remaining steps, you’ll apply that new knowledge to implement the routes for a sample REST API.

      Step 5 — Implementing Your First REST API Route

      In this step, you will install Express in your application. Express is a popular web framework for Node.js that you will use to implement your REST API routes in this project. The first route you will implement will allow you to fetch all users from the API using a GET request. The user data will be retrieved from the database using Prisma Client.

      Go ahead and install Express with the following command:

      Since you’re using TypeScript, you’ll also want to install the respective types as development dependencies. Run the following command to do so:

      • npm install @types/express --save-dev

      With the dependencies in place, you can set up your Express application.

      Start by opening your main source file again:

      Now delete all the code in index.ts and replace it with the following to start your REST API:

      my-blog/src/index.ts

      import { PrismaClient } from '@prisma/client'
      import express from 'express'
      
      const prisma = new PrismaClient()
      const app = express()
      
      app.use(express.json())
      
      // ... your REST API routes will go here
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Here’s a quick breakdown of the code:

      1. You import PrismaClient and express from the respective npm packages.
      2. You instantiate PrismaClient by calling the constructor and obtain an instance called prisma.
      3. You create your Express app by calling express().
      4. You add the express.json() middleware to ensure JSON data can be processed properly by Express.
      5. You start the server on port 3000.

      Now you can implement your first route. Between the calls to app.use and app.listen, add the following code:

      my-blog/src/index.ts

      . . .
      app.use(express.json())
      
      app.get('/users', async (req, res) => {
        const users = await prisma.user.findMany()
        res.json(users)
      })
      
      app.listen(3000, () =>
      console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Once added, save and exit your file. Then start your local web server using the following command:

      You will receive the following output:

      Output

      REST API server ready at: http://localhost:3000

      To access the /users route you can point your browser to http://localhost:3000/users or any other HTTP client.

      In this tutorial, you will test all REST API routes using curl, a terminal-based HTTP client.

      Note: If you prefer to use a GUI-based HTTP client, you can use alternatives like Postwoman or the Advanced REST Client.

      To test your route, open up a new terminal window or tab (so that your local web server can keep running) and execute the following command:

      • curl http://localhost:3000/users

      You will receive the User data that you created in the previous step:

      Output

      [{"id":1,"email":"alice@prisma.io","name":"Alice"}]

      Note that the posts array is not included this time. This is because you’re not passing the include option to the findMany call in the implementation of the /users route.

      You’ve implemented your first REST API route at /users. In the next step you will implement the remaining REST API routes to add more functionality to your API.

      Step 6 — Implementing the Remaining REST API Routes

      In this step, you will implement the remaining REST API routes for your blogging application. At the end, your web server will serve various GET, POST, PUT, and DELETE requests.

      Here is an overview of the different routes you will implement:

      HTTP Method Route Description
      GET /feed Fetches all published posts.
      GET /post/:id Fetches a specific post by its ID.
      POST /user Creates a new user.
      POST /post Creates a new post (as a draft).
      PUT /post/publish/:id Sets the published field of a post to true.
      DELETE post/:id Deletes a post by its ID.

      Go ahead and implement the remaining GET routes first.

      Open up the index.ts with the following command:

      Next, add the following code following the implementation of the /users route:

      my-blog/src/index.ts

      . . .
      
      app.get('/feed', async (req, res) => {
        const posts = await prisma.post.findMany({
          where: { published: true },
          include: { author: true }
        })
        res.json(posts)
      })
      
      app.get(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.findOne({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Save and exit your file.

      This code implements the API routes for two GET requests:

      • /feed: Returns a list of published posts.
      • /post/:id: Returns a specific post by its ID.

      Prisma Client is used in both implementations. In the /feed route implementation, the query you send with Prisma Client filters for all Post records where the published column contains the value true. Additionally, the Prisma Client query uses include to also fetch the related author information for each returned post. In the /post/:id route implementation, you are passing the ID that is retrieved from the URL’s path in order to read a specific Post record from the database.

      You can stop the server hitting CTRL+C on your keyboard. Then, restart the server using:

      To test the /feed route, you can use the following curl command:

      • curl http://localhost:3000/feed

      Since no posts have been published yet, the response is an empty array:

      Output

      []

      To test the /post/:id route, you can use the following curl command:

      • curl http://localhost:3000/post/1

      This will return the post you initially created:

      Output

      {"id":1,"title":"Hello World","content":null,"published":false,"authorId":1}

      Next, implement the two POST routes. Add the following code to index.ts following the implementations of the three GET routes:

      my-blog/src/index.ts

      . . .
      
      app.post(`/user`, async (req, res) => {
        const result = await prisma.user.create({
          data: { ...req.body },
        })
        res.json(result)
      })
      
      app.post(`/post`, async (req, res) => {
        const { title, content, authorEmail } = req.body
        const result = await prisma.post.create({
          data: {
            title,
            content,
            published: false,
            author: { connect: { email: authorEmail } },
          },
        })
        res.json(result)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Once you’re done, save and exit your file.

      This code implements the API routes for two POST requests:

      • /user: Creates a new user in the database.
      • /post: Creates a new post in the database.

      Like before, Prisma Client is used in both implementations. In the /user route implementation, you’re passing in the values from the body of the HTTP request to the Prisma Client create query.

      The /post route is a bit more involved: Here you can’t directly pass in the values from the body of the HTTP request; instead you first need to manually extract them to pass them to the Prisma Client query. The reason for this is that the structure of the JSON in the request body does not match the structure that’s expected by Prisma Client, so you need to manually create the expected structure.

      You can test the new routes by stopping the server with CTRL+C. Then, restart the server using:

      To create a new user via the /user route, you can send the following POST request with curl:

      • curl -X POST -H "Content-Type: application/json" -d '{"name":"Bob", "email":"bob@prisma.io"}' http://localhost:3000/user

      This will create a new user in the database, printing the following output:

      Output

      {"id":2,"email":"bob@prisma.io","name":"Bob"}

      To create a new post via the /post route, you can send the following POST request with curl:

      • curl -X POST -H "Content-Type: application/json" -d '{"title":"I am Bob", "authorEmail":"bob@prisma.io"}' http://localhost:3000/post

      This will create a new post in the database and connect it to the user with the email bob@prisma.io. It prints the following output:

      Output

      {"id":2,"title":"I am Bob","content":null,"published":false,"authorId":2}

      Finally, you can implement the PUT and DELETE routes.

      Open up index.ts with the following command:

      Next, following the implementation of the two POST routes, add the highlighted code:

      my-blog/src/index.ts

      . . .
      
      app.put('/post/publish/:id', async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.update({
          where: { id: Number(id) },
          data: { published: true },
        })
        res.json(post)
      })
      
      app.delete(`/post/:id`, async (req, res) => {
        const { id } = req.params
        const post = await prisma.post.delete({
          where: { id: Number(id) },
        })
        res.json(post)
      })
      
      app.listen(3000, () =>
        console.log('REST API server ready at: http://localhost:3000'),
      )
      

      Save and exit your file.

      This code implements the API routes for one PUT and one DELETE request:

      • /post/publish/:id (PUT): Publishes a post by its ID.
      • /post/:id (DELETE): Deletes a post by its ID.

      Again, Prisma Client is used in both implementations. In the /post/publish/:id route implementation, the ID of the post to be published is retrieved from the URL and passed to the update query of Prisma Client. The implementation of the /post/:id route to delete a post in the database also retrieves the post ID from the URL and passes it to the delete query of Prisma Client.

      Again, stop the server with CTRL+C on your keyboard. Then, restart the server using:

      You can test the PUT route with the following curl command:

      • curl -X PUT http://localhost:3000/post/publish/2

      This is going to publish the post with an ID value of 2. If you resend the /feed request, this post will now be included in the response.

      Finally, you can test the DELETE route with the following curl command:

      • curl -X DELETE http://localhost:3000/post/1

      This is going to delete the post with an ID value of 1. To validate that the post with this ID has been deleted, you can resend a GET request to the /post/1 route.

      In this step, you implemented the remaining REST API routes for your blogging application. The API now responds to various GET, POST, PUT, and DELETE requests and implements functionality to read and write data in the database.

      Conclusion

      In this article, you created a REST API server with a number of different routes to create, read, update, and delete user and post data for a sample blogging application. Inside of the API routes, you are using the Prisma Client to send the respective queries to your database.

      As next steps, you can implement additional API routes or extend your database schema using Prisma Migrate. Be sure to visit the Prisma documentation to learn about different aspects of Prisma and explore some ready-to-run example projects in the prisma-examples repository—using tools such as GraphQL or grPC APIs.



      Source link