One place for hosting & domains

      Prisma

      How To Build a GraphQL API with Prisma and Deploy to DigitalOcean’s App Platform


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      GraphQL is a query language for APIs that consists of a schema definition language and a query language, which allows API consumers to fetch only the data they need to support flexible querying. GraphQL enables developers to evolve the API while meeting the different needs of multiple clients, for example iOS, Android, and web variants of an app. Moreover, the GraphQL schema adds a degree of type safety to the API while also serving as a form of documentation for your API.

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

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

      Prisma facilitates working with databases for application developers who want to focus on implementing value-adding features instead of spending time on complex database workflows (such as schema migrations or writing complicated SQL queries).

      In this tutorial, you will use GraphQL and Prisma in combination as their responsibilities complement each other. GraphQL provides a flexible interface to your data for use in clients, such as frontends and mobile apps—GraphQL isn’t tied to any specific database. This is where Prisma comes in to handle the interaction with the database where your data will be stored.

      DigitalOcean’s App Platform provides a seamless way to deploy applications and provision databases in the cloud without worrying about infrastructure. This reduces the operational overhead of running an application in the cloud; especially with the ability to create a managed PostgreSQL database with daily backups and automated failover. App Platform has native Node.js support streamlining deployment.

      You’ll build a GraphQL API for a blogging application in JavaScript using Node.js. You will first use Apollo Server to build the GraphQL API backed by in-memory data structures. You will then deploy the API to the DigitalOcean App Platform. Finally you will use Prisma to replace the in-memory storage and persist the data in a PostgreSQL database and deploy the application again.

      At the end of the tutorial, you will have a Node.js GraphQL API deployed to DigitalOcean, which handles GraphQL requests sent over HTTP and performs CRUD operations against the PostgreSQL database.

      You can find the code for this project in the DigitalOcean Community respository.

      Prerequisites

      Before you begin this guide you’ll need the following:

      Basic familiarity with JavaScript, Node.js, GraphQL, and PostgreSQL is helpful, but not strictly required for this tutorial.

      Step 1 — Creating the Node.js Project

      In this step, you will set up a Node.js project with npm and install the dependencies apollo-server and graphql.

      This project will be the foundation for the GraphQL API that you’ll build and deploy throughout this tutorial.

      First, create a new directory for your project:

      Next, navigate into the directory and initialize an empty npm project:

      • cd prisma-graphql
      • npm init --yes

      This command creates a minimal package.json file that is used as the configuration file for your npm project.

      You will receive the following output:

      Output

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

      You’re now ready to configure TypeScript in your project.

      Execute the following command to install the necessary dependencies:

      • npm install apollo-server graphql --save

      This installs two packages as dependencies in your project:

      • apollo-server: The HTTP library that you use to define how GraphQL requests are resolved and how to fetch data.
      • graphql: is the library you’ll use to build the GraphQL schema.

      You’ve created your project and installed the dependencies. In the next step you will define the GraphQL schema.

      Step 2 — Defining the GraphQL Schema and Resolvers

      In this step, you will define the GraphQL schema and corresponding resolvers. The schema will define the operations that the API can handle. The resolvers will define the logic for handling those requests using in-memory data structures, which you will replace with database queries in the next step.

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

      Then run the following command to create the file for the schema:

      Now add the following code to the file:

      prisma-graphql/src/schema.js

      const { gql } = require('apollo-server')
      
      const typeDefs = gql`
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createDraft(content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      `
      

      Here you define the GraphQL schema using the gql tagged template. A schema is a collection of type definitions (hence typeDefs) that together define the shape of queries that can be executed against your API. This will convert the GraphQL schema string into the format that Apollo expects.

      The schema introduces three types:

      • Post: Defines the type for a post in your blogging app and contains four fields where each field is followed by its type, for example, String.
      • Query: Defines the feed query which returns multiple posts as denoted by the square brackets and the post query which accepts a single argument and returns a single Post.
      • Mutation: Defines the createDraft mutation for creating a draft Post and the publish mutation which accepts an id and returns a Post.

      Note that every GraphQL API has a query type and may or may not have a mutation type. These types are the same as a regular object type, but they are special because they define the entry point of every GraphQL query.

      Next, add the posts array to the src/schema.js file, below the typeDefs variable:

      prisma-graphql/src/schema.js

      ...
      const posts = [
        {
          id: 1,
          title: 'Subscribe to GraphQL Weekly for community news ',
          content: 'https://graphqlweekly.com/',
          published: true,
        },
        {
          id: 2,
          title: 'Follow DigitalOcean on Twitter',
          content: 'https://twitter.com/digitalocean',
          published: true,
        },
        {
          id: 3,
          title: 'What is GraphQL?',
          content: 'GraphQL is a query language for APIs',
          published: false,
        },
      ]
      

      You define the posts array with three pre-defined posts. Notice that the structure of each post object matches the Post type you defined in the schema. This array holds the posts that will be served by the API. In a subsequent step, you will replace the array once the database and Prisma Client are introduced.

      Next, define the resolvers object below the posts array you just defined:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return posts.filter((post) => post.published)
          },
          post: (parent, args) => {
            return posts.find((post) => post.id === Number(args.id))
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            posts.push({
              id: posts.length + 1,
              title: args.title,
              content: args.content,
              published: false,
            })
            return posts[posts.length - 1]
          },
          publish: (parent, args) => {
            const postToPublish = posts.find((post) => post.id === Number(args.id))
            postToPublish.published = true
            return postToPublish
          },
        },
        Post: {
          content: (parent) => parent.content,
          id: (parent) => parent.id,
          published: (parent) => parent.published,
          title: (parent) => parent.title,
        },
      }
      
      
      module.exports = {
        resolvers,
        typeDefs,
      }
      

      You define the resolvers following the same structure as the GraphQL schema. Every field in the schema’s types has a corresponding resolver function whose responsibility is to return the data for that field in your schema. For example, the Query.feed() resolver will return the published posts by filtering the posts array.

      Resolver functions receive four arguments:

      • parent: The parent is the return value of the previous resolver in the resolver chain. For top-level resolvers, the parent is undefined, because no previous resolver is called. For example, when making a feed query, the query.feed() resolver will be called with parent’s value undefined and then the resolvers of Post will be called where parent is the object returned from the feed resolver.
      • args: This argument carries the parameters for the query, for example, the post query, will receive the id of the post to be fetched.
      • context: An object that gets passed through the resolver chain that each resolver can write to and read from, which allows the resolvers to share information.
      • info: An AST representation of the query or mutation. You can read more about the details in part III of this series: Demystifying the info Argument in GraphQL Resolvers.

      Since the context and info are not necessary in these resolvers, only parent and args are defined.

      Save and exit the file once you’re done.

      Note: When a resolver returns the same field as the resolver’s name, like the four resolvers for Post, Apollo Server will automatically resolve those. This means you don’t have to explicitly define those resolvers.

      -  Post: {
      -    content: (parent) => parent.content,
      -    id: (parent) => parent.id,
      -    published: (parent) => parent.published,
      -    title: (parent) => parent.title,
      -  },
      

      Finally, you export the schema and resolvers so that you can use them in the next step to instantiate the server with Apollo Server.

      Step 3 — Creating the GraphQL Server

      In this step, you will create the GraphQL server with Apollo Server and bind it to a port so that the server can accept connections.

      First, run the following command to create the file for the server:

      Now add the following code to the file:

      prisma-graphql/src/server.js

      const { ApolloServer } = require('apollo-server')
      const { resolvers, typeDefs } = require('./schema')
      
      const port = process.env.PORT || 8080
      
      new ApolloServer({ resolvers, typeDefs }).listen({ port }, () =>
        console.log(`Server ready at: http://localhost:${port}`),
      )
      

      Here you instantiate the server and pass the schema and resolvers from the previous step.

      The port the server will bind to is set from the PORT environment variable and if not set, it will default to 8080. The PORT environment variable will be automatically set by App Platform and ensure your server can accept connections once deployed.

      Save and exit the file.

      Your GraphQL API is ready to run. Start the server with the following command:

      You will receive the following output:

      Output

      Server ready at: http://localhost:8080

      It’s considered good practice to add a start script to your package.json so that the entry point to your server is clear. Moreover, this will allow App Platform to start the server once deployed.

      To do so, add the following line to the "scripts" object in package.json:

      package.json

      {
        "name": "prisma-graphql",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "test": "echo "Error: no test specified" && exit 1",
          "start": "node ./src/server.js"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "dependencies": {
          "apollo-server": "^2.18.2",
          "graphql": "^15.3.0"
        }
      }
      

      Save and exit the file once you’re finished.

      Now you can start the server with the following command:

      To test the GraphQL API, open the URL from the output, which will lead you to the GraphQL Playground.

      GraphQL Playground

      The GraphQL Playground is an IDE where you can test the API by sending queries and mutations.

      For example, to test the feed query which only returns published posts, enter the following query to the left side of the IDE and send the query by pressing the play button:

      query {
        feed {
          id
          title
          content
          published
        }
      }
      

      The response will show a title of Subscribe to GraphQL Weekly with its URL and Follow DigitalOcean on Twitter with its URL.

      GraphQL query

      To test the createDraft mutation, enter the following mutation:

      mutation {
        createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
          id
          title
          content
          published
        }
      }
      

      After you submit the mutation, using the play button, you will receive Deploying a GraphQL API to DigitalOcean within the title field as part of the response.

      GraphQL mutation

      Note: You can choose which fields to return from the mutation by adding or removing fields within the curly braces following createDraft. For example, if you wanted to only return the id and title you could send the following mutation:

      mutation {
        createDraft(title: "Deploying a GraphQL API to DigitalOcean") {
          id
          title
        }
      }
      

      You have successfully created and tested the GraphQL server. In the next step, you will create a GitHub repository for the project.

      Step 4 — Creating the GitHub Repository

      In this step, you will create a GitHub repository for your project and push your changes so that the GraphQL API can be automatically deployed from GitHub to App Platform.

      Begin by initializing a repository from the prisma-graphql folder:

      Next, use the following two commands to commit the code to the repository:

      • git add src package-lock.json package.json
      • git commit -m 'Initial commit'

      Now that the changes have been committed to your local repository, you will create a repository in GitHub and push your changes.

      Go to GitHub to create a new repository. For consistency, name the repository prisma-graphql and then click Create repository.

      After the repository was created, push the changes with the following commands, which includes renaming the default local branch to main:

      • git remote add origin git@github.com:your_github_username/prisma-graphql.git
      • git branch -M main
      • git push --set-upstream origin main

      You have successfully committed and pushed the changes to GitHub. Next, you will connect the repository to App Platform and deploy the GraphQL API.

      Step 5 — Deploying to App Platform

      In this step, you will connect the GitHub repository you created in the previous step to DigitalOcean and configure App Platform so that the GraphQL API can be automatically deployed when you push changes to GitHub.

      First, go to the App Platform and click on the Launch Your App button.

      You will see a button to link your GitHub account.

      Link Your GitHub Acccount

      Click on it, and you will be redirected to GitHub.

      Click Install & Authorize and you will be redirected back to DigitalOcean.

      Choose the repository your_github_username/prisma-graphql and click Next.

      Name your app and pick a branch to deploy from

      Choose the region you want to deploy your app to and click Next.

      Configure your app

      Here you can customize the configuration for the app. Ensure that the Run Command is npm start. By default, App Platform will set the HTTP port to 8080, which is the same port that you’ve configured your GraphQL server to bind to.

      Click Next and you will be prompted to pick the plan.

      Select Basic and then click Launch Basic App. You will be redirected to the app page, where you will see the progress of the initial deployment.

      Once the build finishes, you will get a notification indicating that your app is deployed.

      App page

      You can now visit your deployed GraphQL API at the URL below the app’s name. It will be under the ondigitalocean.app subdomain. If you open the URL, the GraphQL Playground will open the same way as it did in Step 3 of the tutorial.

      You have successfully connected your repository to App Platform and deployed your GraphQL API. Next you will evolve your app and replace the in-memory data of the GraphQL API with a database.

      Step 6 — Setting Up Prisma with PostgreSQL

      So far the GraphQL API you built used the in-memory posts array to store data. This means that if your server restarts, all changes to the data will be lost. To ensure that your data is safely persisted, you will replace the posts array with a PostgreSQL database and use Prisma to access the data.

      In this step, you will install the Prisma CLI, create your initial Prisma schema, set up PostgreSQL locally with Docker, and connect Prisma to it.

      The Prisma schema is the main configuration file for your Prisma setup and contains your database schema.

      Begin by installing the Prisma CLI with the following command:

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

      The Prisma CLI will help with database workflows such as running database migrations and generating Prisma Client.

      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:

      prisma-graphql/docker-compose.yml

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

      This Docker Compose configuration file is responsible for starting the official PostgreSQL Docker image on your machine. The POSTGRES_USER and POSTGRES_PASSWORD environment variables set the credentials for the superuser (a user with admin privileges). You will also use these credentials to connect Prisma to the database. Finally, you define a volume where PostgreSQL will store its data, and bind the 5432 port on your machine to the same port in the Docker container.

      Save and exit the file.

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

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

      This will output something similar to:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 198f9431bf73 postgres:10.3 "docker-entrypoint.s…" 45 seconds ago Up 11 seconds 0.0.0.0:5432->5432/tcp prisma-graphql_postgres_1

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

      Note that as a best practice, all invocations of the Prisma CLI should be prefixed with npx. This ensures it’s using your local installation.

      After running 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 (in which you 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:

      Adjust the DATABASE_URL environment variable to look as follows:

      prisma-graphql/prisma/.env

      DATABASE_URL="postgresql://test-user:test-password@localhost:5432/my-blog?schema=public"
      

      Note that you’re using the database credentials test-user and test-password, which are specified in the Docker Compose file. To learn more about the format of the connection URL, visit the Prisma docs.

      You have successfully started PostgreSQL and configured Prisma using the Prisma schema. In the next step, you will define your data model for the blog and use Prisma Migrate to create the database schema.

      Step 7 — Defining the Data Model with Prisma Migrate

      Now you will define your data model in the Prisma schema file you’ve just created. 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 blog, the main entities of the application will be users and posts. In this step, you will define a Post model with a similar structure to the Post type in the GraphQL schema. In a later step, you will evolve the app and add a User model.

      Note: The GraphQL API can be seen as an abstraction layer for your database. When building a GraphQL API, it’s common for the GraphQL schema to closely resemble your database schema. However, as an abstraction, the two schemas won’t necessarily have the same structure, thereby allowing you to control which data you want to expose over the API. This is because some data might be considered sensitive or irrelevant for the API layer.

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

      Open your schema.prisma file from the project’s folder where package.json is located:

      • nano prisma/schema.prisma

      Note: You can verify from the terminal in which folder you are with the pwd command, which will output the current working directory. Additionally, listing the files with the ls command will help you navigate your file system.

      Add the following model definitions to it:

      prisma-graphql/prisma/schema.prisma

      ...
      model Post {
        id        Int     @default(autoincrement()) @id
        title     String
        content   String?
        published Boolean @default(false)
      }
      

      You are defining a model called Post with a number of fields. The model will be mapped to a database table; the fields represent the individual columns.

      The id fields have the following field attributes:

      • @default(autoincrement()): This sets an auto-incrementing default value for the column.
      • @id: This sets the column as the primary key for the table.

      Save and exit the file once you’re done.

      With the model in place, you can now create the corresponding table in the database using Prisma Migrate. This is a two-step process that involves creating the migration files and running them.

      Open up your terminal again and run the following command:

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

      This command creates a new migration on your file system. 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 file system).

      Your prisma/migrations directory will now be populated with the files necessary to carry out the migration.

      Note: If you’ve already used Prisma Migrate with the my-blog database and there is an inconsistency between the migrations in the prisma/migration folder and the database schema you will enounter the following error:

      Output

      Error: There are more migrations in the database than locally. This must not happen.

      You can resolve this error by dropping the database with the following command:

      • psql postgresql://test-user:test-password@localhost:5432/postgres -c "DROP DATABASE "my-blog""

      Alternatively, you can stop the PostgreSQL container and remove the postgres volume defined in docker-compose.yml, which contains the data for the database. Beware that this will delete all data in the database. To do so, run the following command:

      The down command will stop the PostgreSQL container and the -v option will remove all volumes, thereby deleting all databases.

      To start PostgreSQL again, run the following command:

      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

      Prisma Migrate now generates the SQL statements that are required for the migration and sends them to the database. You will receive the following if the migration was carried out successfully:

      Output

      🚀 Done with 1 migration in 234ms.

      You’ve now created your database schema. In the next step, you will install Prisma Client and use it in your GraphQL resolvers.

      Step 8 — Using Prisma Client in the GraphQL Resolvers

      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 application. In this step, you’ll install Prisma Client in your project.

      Open up your terminal again and install the Prisma Client npm package:

      • npm install @prisma/client

      Note: Prisma Client gives you rich auto-completion by generating code based on your Prisma schema to the node_modules folder. To generate the code you use the npx prisma generate command. This is typically done after you create and run a new migration. On the first install, however, this is not necessary as it will automatically be generated for you in a postinstall hook.

      With the database and GraphQL schema created, and Prisma Client installed, you will now use Prisma Client in the GraphQL resolvers to read and write data in the database. You’ll do this by replacing the posts array, which you’ve used so far to hold your data.

      Begin by creating the following file:

      Add the following:

      prisma-graphql/src/db.js

      const { PrismaClient } = require('@prisma/client')
      
      module.exports = {
        prisma: new PrismaClient(),
      }
      

      This imports Prisma Client, creates an instance of it, and exports the instance that you’ll use in your resolvers.

      Now save and close the src/db.js file.

      Next, you will import the prisma instance into src/schema.js. To do so, open src/schema.js:

      Then import prisma from ./db at the top of the file:

      prisma-graphql/src/schema.js

      const { prisma } = require('./db')
      ...
      

      Then delete the posts array:

      prisma-graphql/src/schema.js

      -const posts = [
      -  {
      -    id: 1,
      -    title: 'Subscribe to GraphQL Weekly for community news ',
      -    content: 'https://graphqlweekly.com/',
      -    published: true,
      -  },
      -  {
      -    id: 2,
      -    title: 'Follow DigitalOcean on Twitter',
      -    content: 'https://twitter.com/digitalocean',
      -    published: true,
      -  },
      -  {
      -    id: 3,
      -    title: 'What is GraphQL?',
      -    content: 'GraphQL is a query language for APIs',
      -    published: false,
      -  },
      -]
      

      Now you will update the Query resolvers to fetch published posts from the database. Update the resolvers.Query object with the following resolvers:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
      

      Here, you’re using two Prisma Client queries:

      • findMany: Fetches posts whose publish field is false.
      • findOne: Fetches a single post whose id field equals the id GraphQL argument.

      Note, that as per the GraphQL specification, the ID type is serialized the same way as a String. Therefore you convert to a Number because the id in the Prisma schema is an int.

      Next, you will update the Mutation resolver to save and update posts in the database. Update the resolvers.Mutation Object with the following resolvers:

      prisma-graphql/src/schema.js

      const resolvers = {
        ...
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: {
                id: Number(args.id),
              },
              data: {
                published: true,
              },
            })
          },
        },
      }
      

      You’re using two Prisma Client queries:

      • create: Create a Post record.
      • update: Update the published field of the Post record whose id matches the one in the query argument.

      Your schema.js should now look as follows:

      prisma-graphql/src/schema.js

      const { gql } = require('apollo-server')
      const { prisma } = require('./db')
      
      const typeDefs = gql`
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createDraft(content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      `
      
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: {
                id: Number(args.id),
              },
              data: {
                published: true,
              },
            })
          },
        },
      }
      
      module.exports = {
        resolvers,
        typeDefs,
      }
      

      Save and close the file.

      Now that you’ve updated the resolvers to use Prisma Client, start the server to test the flow of data between the GraphQL API and the database with the following command:

      Once again, you will receive the following output:

      Output

      Server ready at: http://localhost:8080

      Open the GraphQL playground at the address from the output and test the GraphQL API using the same queries from Step 3.

      Now you will commit your changes so that the changes can be deployed to App Platform.

      To avoid committing the node_modules folder and the prisma/.env file, begin by creating a .gitignore file:

      Add the following to the file:

      prisma-graphql/.gitignore

      node_modules
      prisma/.env
      

      Save and exit the file.

      Then run the following two commands to commit the changes:

      • git add .
      • git commit -m 'Add Prisma'

      Next you’ll add a PostgreSQL database to your app in App Platform.

      Step 9 — Creating and Migrating the PostgreSQL Database in App Platform

      In this step, you will add a PostgreSQL database to your app in App Platform. Then you will use Prisma Migrate to run the migration against it so that the deployed database schema matches your local database.

      First, go to the App Platform console and choose the prisma-graphql project you created in Step 5.

      Next, go to the Components tab.

      Component Tab

      Click on + Create Component and select Database, which will lead you to a page to configure your database.

      Configure your database

      Choose Dev Database and click Create and Attach.

      You will be redirected back to the Components page, where there will be a progress bar for creating the database.

      Creating database

      After the database has been created, you will run the database migration against the production database on DigitalOcean from your local machine. To run the migration, you will need the connection string of the hosted database. To get it, click on the db icon in the components tab.

      Database information

      Under Connection Details select Connection String in the dropdown and copy the database URL, which will have the following structure:

      postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require
      

      Then, run the following command in your terminal and ensure that you set DATABASE_URL to the same URL you copied:

      • DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate up --experimental

      This will run the migrations against the live database with Prisma Migrate.

      If the migration succeeds you will receive the following:

      Output

      🚀 Done with 1 migration in 234ms.

      You have successfully migrated the production database on DigitalOcean, which now matches the Prisma schema.

      Now you can deploy your app by pushing your Git changes with the following command:

      Note: App Platform will make the DATABASE_URL environment variable available to your application at run-time. Prisma Client will use that environment variable using the env("DATABASE_URL") in the datasource block of your Prisma schema.

      This will automatically trigger a build. If you open App Platform console, you will have a Deploying progress bar.

      Deploying

      Once the deployment succeeds, you will receive a Deployed successfully message.

      You’ve now backed up your deployed GraphQL API with a database. Open the Live App, which will lead you to the GraphQL Playground. Test the GraphQL API using the same queries from Step 3.

      In the final step you will evolve the GraphQL API by adding the User model.

      Step 10 — Adding the User Model

      Your GraphQL API for blogging has a single entity named Post. In this step, you’ll evolve the API by defining a new model in the Prisma schema and adapting the GraphQL schema to make use of the new model. You will introduce a User model with a one-to-many relation to the Post model. This will allow you to represent the author of posts and associate multiple posts to each user. Then you will evolve the GraphQL schema to allow creating users and associating posts with users through the API.

      First, open the Prisma schema and add the following:

      prisma-graphql/prisma/schema.prisma

      ...
      model Post {
        id        Int     @id @default(autoincrement())
        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-graphql-api-with-prisma-and-deploy-to-digitalocean-s-app-platform)
        authorId  Int?
      }
      
      model User {
        id    Int    @id @default(autoincrement())
        email String @unique
        name  String
        posts Post[]
      }
      

      You’ve added the following to the Prisma schema:

      • The User model to represent users.
      • Two relation fields: author and posts. Relation fields define connections between models at the Prisma level and do not exist in the database. These fields are used to generate the Prisma Client and to access relations with Prisma Client.
      • The authorId field, which is referenced by the @relation attribute. Prisma will create a foreign key in the database to connect Post and User.

      Note that the author field in the Post model is optional. That means you’ll be able to create posts unassociated with a user.

      Save and exit the file once you’re done.

      Next, save and run the migration locally with the following commands:

      • npx prisma migrate save --experimental --name "add-user"
      • npx prisma migrate up --experimental

      After the migration has succeeded, generate Prisma Client so that you can make use of the new fields in the next step:

      Now you will run the migration against the production database on App Platform so that the database schema is the same as your local database. Run the following command in your terminal and set DATABASE_URL to the connection URL from App Platform:

      • DATABASE_URL="postgresql://db:some_password@unique_identifier.db.ondigitalocean.com:25060/db?sslmode=require" npx prisma migrate up --experimental

      You will receive the following:

      Output

      🚀 Done with 1 migration in 274ms.

      You will now update the GraphQL schema and resolvers to make use of the updated database schema.

      Open the src/schema.js file and add update typeDefs as follows:

      prisma-graphql/src/schema.js

      ...
      const typeDefs = gql`
        type User {
          email: String!
          id: ID!
          name: String
          posts: [Post!]!
        }
      
        type Post {
          content: String
          id: ID!
          published: Boolean!
          title: String!
          author: User
        }
      
        type Query {
          feed: [Post!]!
          post(id: ID!): Post
        }
      
        type Mutation {
          createUser(data: UserCreateInput!): User!
          createDraft(authorEmail: String, content: String, title: String!): Post!
          publish(id: ID!): Post
        }
      
        input UserCreateInput {
          email: String!
          name: String
          posts: [PostCreateWithoutAuthorInput!]
        }
      
        input PostCreateWithoutAuthorInput {
          content: String
          published: Boolean
          title: String!
        }
      `
      ...
      

      In this updated code, you’re adding the following changes to the GraphQL schema:

      • The User type, which returns an array of Post.
      • The author field to the Post type.
      • The createUser mutation, which expects the UserCreateInput as its input type.
      • The PostCreateWithoutAuthorInput input type used in the UserCreateInput input for creating posts as part of the createUser mutation.
      • The authorEmail optional argument to the createDraft mutation.

      With the schema updated, you will now update the resolvers to match the schema.

      Update the resolvers object as follows:

      prisma-graphql/src/schema.js

      ...
      const resolvers = {
        Query: {
          feed: (parent, args) => {
            return prisma.post.findMany({
              where: { published: true },
            })
          },
          post: (parent, args) => {
            return prisma.post.findOne({
              where: { id: Number(args.id) },
            })
          },
        },
        Mutation: {
          createDraft: (parent, args) => {
            return prisma.post.create({
              data: {
                title: args.title,
                content: args.content,
                published: false,
                author: args.authorEmail && {
                  connect: { email: args.authorEmail },
                },
              },
            })
          },
          publish: (parent, args) => {
            return prisma.post.update({
              where: { id: Number(args.id) },
              data: {
                published: true,
              },
            })
          },
          createUser: (parent, args) => {
            return prisma.user.create({
              data: {
                email: args.data.email,
                name: args.data.name,
                posts: {
                  create: args.data.posts,
                },
              },
            })
          },
        },
        User: {
          posts: (parent, args) => {
            return prisma.user
              .findOne({
                where: { id: parent.id },
              })
              .posts()
          },
        },
        Post: {
          author: (parent, args) => {
            return prisma.post
              .findOne({
                where: { id: parent.id },
              })
              .author()
          },
        },
      }
      

      Let’s break down the changes to the resolvers:

      • The createDraft mutation resolver now uses the authorEmail argument (if passed) to create a relation between the created draft and an existing user.
      • The new createUser mutation resolver creates a user and related posts using nested writes.
      • The User.posts and Post.author resolvers define how to resolve the posts and author fields when the User or Post are queried. These use Prisma’s Fluent API to fetch the relations.

      Save and exit the file.

      Start the server to test the GraphQL API:

      Begin by testing the createUser resolver with the following GraphQL mutation:

      mutation {
        createUser(data: { email: "natalia@prisma.io", name: "Natalia" }) {
          email
          id
        }
      }
      

      This will create a user.

      Next, test the createDraft resolver with the following mutation:

      mutation {
        createDraft(
          authorEmail: "hello@prisma.io"
          title: "Deploying a GraphQL API to App Platform"
        ) {
          id
          title
          content
          published
          author {
            id
            name
          }
        }
      }
      

      Notice that you can fetch the author whenever the return value of a query is Post. In this example, the Post.author resolver will be called.

      Finally, commit your changes and push to deploy the API:

      • git add .
      • git commit -m "add user model"
      • git push

      You have successfully evolved your database schema with Prisma Migrate and exposed the new model in your GraphQL API.

      Conclusion

      In this article, you built a GraphQL API with Prisma and GraphQL, and deployed it to DigitalOcean’s App Platform. You defined a GraphQL schema and resolvers with Apollo Server. You then used Prisma Client in your GraphQL resolvers to persist and query data in the PostgreSQL database.

      As a next step, you can further extend the GraphQL API with a query to fetch individual users and a mutation to connect an existing draft to a user.

      If you’re interested in exploring the data in the database, check out Prisma Studio. 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.

      You can find the code for this project in the DigitalOcean Community repository.





      Source link

      Cómo crear una API de REST con Prisma y PostgreSQL


      El autor seleccionó la organización Diversity in Tech Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Prisma es un conjunto de herramientas para bases de datos de código abierto. Consta de tres herramientas principales:

      • Prisma Client: un generador de consultas con seguridad de tipos que se genera de forma automática para Node.js y TypeScript.
      • Prisma Migrate: un sistema de migración y modelado de datos declarativo.
      • Prisma Studio: una GUI para ver y editar datos en su base de datos.

      Estas herramientas pretenden aumentar la productividad de los desarrolladores de aplicaciones en los flujos de trabajo de sus bases de datos. Uno de los principales beneficios de Prisma es el nivel de abstracción que proporciona: en lugar de tener que resolver consultas SQL o migraciones de esquemas complejas, los desarrolladores de aplicaciones pueden razonar acerca de sus datos de forma más intuitiva al utilizar Prisma para trabajar con su base de datos.

      En este tutorial, creará una API de REST para una aplicación de blog pequeña en TypeScript usando Prisma y una base de datos PostgreSQL. Configurará su base de datos PostgreSQL de forma local con Docker e implementará las rutas de la API de REST utilizando Express. Al final del tutorial, tendrá un servidor web que puede responder a varias solicitudes HTTP y leer y escribir datos en la base de datos ejecutándose en su equipo de forma local.

      Requisitos previos

      Para seguir este tutorial, necesitará lo siguiente:

      Es útil, pero no un requisito de este tutorial, tener conocimientos básicos sobre TypeScript y las API de REST.

      Paso 1: Crear su proyecto de TypeScript

      En este paso, configurará un proyecto de TypeScript simple utilizando npm. Este proyecto será la base para la API de REST que creará en el transcurso de este tutorial.

      Primero, cree un directorio nuevo para su proyecto:

      Luego, diríjase al directorio e inicie un proyecto npm vacío. Tenga en cuenta que la opción -y se utiliza para omitir las solicitudes interactivas del comando. Para verlas, elimine -y del comando:

      Para obtener más información sobre estas solicitudes, siga el Paso 1 de Cómo usar módulos Node.js con npm y package.json.

      Obtendrá un resultado similar al siguiente con las respuestas predeterminadas:

      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" }

      Este comando crea un archivo package.json mínimo que utiliza como archivo de configuración de su proyecto npm. Con esto, está listo para configurar TypeScript en su proyecto.

      Ejecute el siguiente comando para realizar la instalación básica de TypeScript:

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

      Este comando instala tres paquetes como dependencias de desarrollo en su proyecto:

      • typescript: la cadena de herramientas de TypeScript.
      • ts-node: un paquete para ejecutar aplicaciones TypeScript sin compilar previamente a JavaScript.
      • @types/node: las definiciones de tipo de TypeScript para Node.js.

      Solo resta añadir un archivo tsconfig.json para garantizar que TypeScript esté configurado de forma adecuada para la aplicación que va a crear.

      Primero, ejecute el siguiente comando para crear el archivo:

      Agregue el siguiente código de JSON al archivo:

      my-blog/tsconfig.json

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

      Guarde el archivo y ciérrelo.

      Esta es una configuración estándar y mínima para un proyecto de TypeScript. Puede encontrar información sobre las propiedades individuales del archivo de configuración en la documentación de TypeScript.

      Ha configurado su proyecto de TypeScript simple usando npm. A continuación, configurará su base de datos PostgreSQL con Docker y la conectará a Prisma.

      Paso 2: Configurar Prisma con PostgreSQL

      En este paso, instalará la CLI de Prisma, creará su archivo de esquema de Prisma inicial, configurará PostgreSQL con Docker y conectará Prisma a la base de datos. El archivo de esquema de Prisma es el archivo de configuración principal de su instalación de Prisma y contiene el esquema de su base de datos.

      Comience por instalar la CLI de Prisma con el siguiente comando:

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

      Se recomienda instalar la CLI de Prisma en el proyecto de forma local (en lugar de realizar una instalación global). Esto ayuda a evitar conflictos de versiones en caso de que tenga más de un proyecto de Prisma en su equipo.

      A continuación, configurará su base de datos PostgreSQL utilizando Docker. Cree un nuevo archivo de Docker Compose con el siguiente comando:

      Luego, añada el siguiente código al archivo nuevo:

      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:
      

      Este archivo de Docker Compose configura una base de datos PostgreSQL a la que se puede acceder a través del puerto 5432 del contenedor de Docker. Tenga en cuenta que estamos utilizando las credenciales de la base de datos sammy (usuario) y your_password (contraseña). Puede modificar estas credenciales y utilizar el nombre de usuario y la contraseña que desee. Guarde el archivo y ciérrelo.

      Ahora que estableció esta configuración, proceda a iniciar el servidor de la base de datos PostgreSQL con el siguiente comando:

      El resultado de este comando será similar al siguiente:

      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

      Puede verificar que el servidor de la base de datos se esté ejecutando con el siguiente comando:

      Obtendrá un resultado similar al siguiente:

      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

      Ahora que el servidor de la base de datos está en ejecución, puede crear su instalación de Prisma. Ejecute el siguiente comando desde la CLI de Prisma:

      Esto imprimirá el siguiente resultado:

      Output

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

      Tenga en cuenta que es recomendable prefijar todas las invocaciones de la CLI de Prisma con npx. Esto garantiza que se utilice su instalación local.

      Cuando ejecutó el comando, la CLI de Prisma creó una nueva carpeta denominada prisma en su proyecto. Contiene estos dos archivos:

      • schema.prisma: el archivo de configuración principal de su proyecto de Prisma (incluirá su modelo de datos).
      • .env: un archivo dotenv para definir la URL de conexión de su base de datos.

      Para asegurarse de que Prisma conozca la ubicación de su base de datos, abra el archivo .env y ajuste la variable de entorno DATABASE_URL.

      Primero, abra el archivo .env:

      Ahora, puede establecer la variable de entorno de la siguiente manera:

      my-blog/prisma/.env

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

      Asegúrese de reemplazar las credenciales de la base de datos por las que especificó en el archivo de Docker Compose. Para obtener más información sobre el formato de la URL de conexión, consulte la documentación de Prisma.

      Cuando termine, guarde y cierre el archivo.

      En este paso, configuró su base de datos PostgreSQL con Docker, instaló la CLI de Prisma y conectó a la base de datos a través de una variable de entorno. En la siguiente sección, definirá el modelo de datos y creará las tablas de su base de datos.

      Paso 3: Definir el modelo de datos y crear tablas de datos

      En este paso, definirá el modelo de datos en el archivo de esquema de Prisma. Luego, asignará ese modelo de datos a la base de datos con Prisma Migrate, que generará y enviará las instrucciones SQL para crear las tablas correspondientes a su modelo de datos. Como está creando una aplicación de blog, las principales entidades de la aplicación serán usuarios y publicaciones.

      Prisma utiliza su propio lenguaje de modelado de datos para definir la forma de los datos de su aplicación.

      Primero, abra el archivo schema.prisma con el siguiente comando:

      • nano prisma/schema.prisma

      Luego, añada las siguientes definiciones del modelo allí. Puede colocar los modelos en la parte inferior del archivo, justo después del bloque 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-es)
        authorId  Int?
      }
      

      Guarde el archivo y ciérrelo.

      Está definiendo dos modelos, denominados User y Post. Cada uno de ellos contiene varios campos que representan las propiedades del modelo. Los modelos se asignarán a las tablas de la base de datos; los campos representan las columnas individuales.

      Tenga en cuenta que hay una relación de uno a varios entre los dos modelos, especificada por los campos de relaciones posts y author en User y Post. Esto significa que se puede asociar un usuario a varias publicaciones.

      Ahora que estableció estos modelos, puede crear las tablas correspondientes en la base de datos utilizando Prisma Migrate. Ejecute el siguiente comando en su terminal:

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

      Este comando crea una migración nueva en su sistema de archivos. A continuación, se presenta una descripción general de las tres opciones que se proporcionan al comando:

      • --experimental: se requiere porque, actualmente, Prisma Migrate está en estado experimental.
      • --create-db: permite a Prisma Migrate crear la base de datos denominada my-blog especificada en la URL de conexión.
      • --name "init": especifica el nombre de la migración (se utilizará para dar nombre a la carpeta de migración que se crea en su sistema de archivos).

      El resultado de este comando será similar al siguiente:

      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-es) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      Puede ver los archivos de migración que se crearon en el directorio prisma/migrations.

      Para ejecutar la migración de su base de datos y crear las tablas para sus modelos de Prisma, ejecute el siguiente comando en su terminal:

      • npx prisma migrate up --experimental

      Obtendrá el siguiente resultado:

      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.

      Ahora, Prisma Migrate generará las instrucciones SQL necesarias para la migración y las enviará a la base de datos. Estas son las instrucciones SQL que crearon las tablas:

      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
      

      En este paso, definió su modelo de datos en el esquema de Prisma y creó las respectivas tablas de bases de datos con Prisma Migrate. En el siguiente paso, instalará Prisma Client en su proyecto para poder consultar la base de datos.

      Paso 4: Explorar consultas de Prisma Client en una secuencia de comandos simple

      Prisma Client es un generador de consultas con seguridad de tipos de generación automática que puede utilizar para leer y escribir datos mediante programación en una base de datos desde una aplicación Node.js o TypeScript. Lo utilizará para acceder a la base de datos con las rutas de su API de REST, en lugar de usar ORM tradicionales, consultas SQL simples, capas de acceso a datos personalizadas o cualquier otro método de comunicación con una base de datos.

      En este paso, instalará Prisma Client y se familiarizará con las consultas que puede enviar. Antes de implementar las rutas de su API de REST en los siguientes pasos, analizaremos algunas consultas de Prisma Client en una secuencia de comandos ejecutable simple.

      Primero, para instalar Prisma Client en su proyecto, abra su terminal e instale el paquete npm de Prisma Client:

      • npm install @prisma/client

      A continuación, cree un directorio nuevo denominado src para alojar sus archivos de origen:

      Ahora, cree un archivo de TypeScript en el directorio nuevo:

      Todas las consultas de Prisma Client devuelven promesas con las que puede usar await en su código. Para hacerlo, deberá enviar las consultas dentro de una función async.

      Añada el siguiente código reutilizable con una función async que se ejecute en su secuencia de comandos:

      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())
      

      A continuación, se presenta una descripción general del código reutilizable:

      1. Se importa el constructor PrismaClient del paquete npm @prisma/client previamente instalado.
      2. Se inicia PrismaClient al invocar al constructor y se obtiene una instancia denominada prisma.
      3. Se define una función async denominada main en la que, a continuación, añadirá las consultas de Prisma Client.
      4. Se invoca la función main y, a la vez, se detectan posibles excepciones y se garantiza que Prisma Client cierre cualquier conexión con bases de datos abierta al invocar prisma.disconnect().

      Ahora que estableció la función main, puede comenzar a añadir consultas de Prisma Client a la secuencia de comandos. Ajuste index.ts para que tenga el siguiente aspecto:

      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())
      

      En este código, está utilizando dos consultas de Prisma Client:

      • create: crea un nuevo registro de User. Tenga en cuenta que, en realidad, está utilizando una escritura anidada, lo que significa que está creando un registro de User y uno de Post en la misma consulta.
      • findMany: lee todos los registros de User existentes de la base de datos. Está proporcionando una opción include, que, adicionalmente, carga los registros de Post relacionados de cada registro de User.

      A continuación, ejecute la secuencia de comandos con el siguiente comando:

      Obtendrá el siguiente resultado en su 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 } ] }

      Nota: Si está utilizando una GUI de base de datos, puede verificar que los datos se hayan creado al revisar las tablas User y Post. De forma alternativa, puede consultar los datos de Prisma Studio al ejecutar npx prisma studio --experimental.

      Ha aprendido a utilizar Prisma Client para leer y escribir datos en su base de datos. En los siguientes pasos, aplicará sus conocimientos nuevos para implementar las rutas de una API de REST de muestra.

      Paso 5: Implementar su primera ruta de la API de REST

      En este paso, instalará Express en su aplicación. Express es un marco web popular para Node.js que utilizará para implementar sus rutas de la API de REST en este proyecto. La primera ruta que implementará le permitirá obtener todos los usuarios de la API utilizando una solicitud GET. Obtendrá los datos de los usuarios de la base de datos utilizando Prisma Client.

      Instale Express con el siguiente comando:

      Como está utilizando TypeScript, también le convendrá instalar los respectivos tipos como dependencias de desarrollo. Para hacerlo, ejecute el siguiente comando:

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

      Ahora que estableció las dependencias, puede configurar su aplicación Express.

      Comience por volver a abrir su archivo de origen principal:

      A continuación, elimine todo el código de index.ts y sustitúyalo por el siguiente para iniciar su API de REST:

      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'),
      )
      

      A continuación, se presenta una descripción breve del código:

      1. Se importan PrismaClient y express de sus respectivos paquetes npm.
      2. Se inicia PrismaClient al invocar al constructor y se obtiene una instancia denominada prisma.
      3. Su aplicación Express se crea al invocar express().
      4. Se añade el software intermedio express.json() para garantizar que Express pueda procesar correctamente los datos de JSON.
      5. Se inicia el servidor en el puerto 3000.

      Con esto, puede implementar su primera ruta. Agregue el siguiente código entre las invocaciones a app.use y 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'),
      )
      

      Una vez que lo haya añadido, guarde y cierre su archivo. A continuación, inicie su servidor web local utilizando el siguiente comando:

      Recibirá el siguiente resultado:

      Output

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

      Para acceder a la ruta /users, puede apuntar su navegador a http://localhost:3000/users o a cualquier otro cliente HTTP.

      En este tutorial, probará todas las rutas de la API de REST utilizando curl, un cliente HTTP basado en terminal.

      Nota: Si prefiere usar un cliente HTTP basado en GUI, puede usar alternativas como Postwoman o el cliente REST avanzado.

      Para probar su ruta, abra una ventana o una pestaña de terminal nueva (para que su servidor web local pueda seguir en ejecución) y ejecute el siguiente comando:

      • curl http://localhost:3000/users

      Obtendrá los datos de User que creó en el paso anterior:

      Output

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

      Tenga en cuenta que la matriz posts no se incluye en este momento. Esto se debe a que no está pasando la opción include a la invocación de findMany en la implementación de la ruta /users.

      Ha implementado su primera ruta de la API de REST en /users. En el siguiente paso, implementará las rutas restantes de la API de REST para añadir más funcionalidad a su API.

      Paso 6: Implementar las rutas restantes de la API de REST

      En este paso, implementará las rutas restantes de la API de REST para su aplicación de blog. Al final, su servidor web proporcionará diversas solicitudes GET, POST, PUT y DELETE.

      A continuación, se presenta una descripción general de las diferentes rutas que implementará:

      Método HTTP Ruta Descripción
      GET /feed Obtiene todas las publicaciones publicadas.
      GET /post/:id Obtiene un publicación específica por su ID.
      POST /user Crea un usuario nuevo.
      POST /post Crea una publicación nueva (como borrador).
      PUT /post/publish/:id Establece el campo published de una publicación en true.
      DELETE post/:id Elimina una publicación por su ID.

      Primero, proceda a ejecutar e implementar las rutas GET restantes.

      Abra index.ts con el siguiente comando:

      A continuación, añada el siguiente código después de la implementación de la ruta /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'),
      )
      

      Guarde y cierre su archivo.

      Este código implementa las rutas de la API para dos solicitudes GET:

      • /feed: devuelve una lista de las publicaciones publicadas.
      • /post/:id: devuelve una publicación específica por su ID.

      Se utiliza Prisma Client en ambas implementaciones. En la implementación de la ruta /feed, la consulta que envía con Prisma Client filtra todos los registros de Post en los que la columna published contiene el valor true. Además, la consulta de Prisma Client utiliza include para obtener la información relacionada de author de cada publicación que se devuelve. En la implementación de la ruta /post/:id, pasa la ID que se obtiene de la ruta de la URL para poder leer un registro de Post específico de la base de datos.

      Puede detener el servidor al pulsar CTRL+C en el teclado. A continuación, reinicie el servidor utilizando lo siguiente:

      Para probar la ruta /feed, puede usar el siguiente comando curl:

      • curl http://localhost:3000/feed

      Como aún no se ha publicado ninguna publicación, la respuesta es una matriz vacía:

      Output

      []

      Para probar la ruta /post/:id, puede usar el siguiente comando curl:

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

      Este comando devolverá la publicación que creó inicialmente:

      Output

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

      A continuación, ejecute las dos rutas de POST. Añada el siguiente código a index.ts después de las implementaciones de las tres rutas de 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'),
      )
      

      Cuando termine, guarde y cierre el archivo.

      Este código implementa las rutas de la API para dos solicitudes POST:

      • /user: crea un usuario nuevo en la base de datos.
      • /post: crea una publicación nueva en la base de datos.

      Al igual que anteriormente, se utiliza Prisma Client en ambas implementaciones. En la implementación de la ruta /user, pasa los valores del cuerpo de la solicitud HTTP a la consulta create de Prisma Client.

      La ruta /post es un poco más compleja: como no puede pasar los valores del cuerpo de la solicitud HTTP directamente, primero, deberá extraerlos de forma manual para pasarlos a la consulta de Prisma Client. Esto se debe a que la estructura de JSON en el cuerpo de la solicitud no coincide con la que espera Prisma Client, por lo tanto, debe crear la estructura esperada de forma manual.

      Puede probar las rutas nuevas al detener el servidor con CTRL+C. A continuación, reinicie el servidor utilizando lo siguiente:

      Para crear un usuario nuevo a través de la ruta /user, puede enviar la siguiente solicitud POST con curl:

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

      Con esto, se creará un usuario nuevo en la base de datos y se imprimirá el siguiente resultado:

      Output

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

      Para crear una publicación nueva a través de la ruta /post, puede enviar la siguiente solicitud POST con curl:

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

      Con esto, se creará una publicación nueva en la base de datos que se conectará al usuario con el correo electrónico bob@prisma.io. Se imprime el siguiente resultado:

      Output

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

      Por último, puede implementar las rutas PUT y DELETE.

      Abra index.ts con el siguiente comando:

      A continuación, después de la implementación de las dos rutas de POST, añada el código resaltado:

      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'),
      )
      

      Guarde y cierre su archivo.

      Este código implementa las rutas de la API para una solicitud PUT y una DELETE:

      • /post/public/:id (PUT): publica una publicación por su ID.
      • /post/:id (DELETE): elimina una publicación por su ID.

      Nuevamente, se utiliza Prisma Client en ambas implementaciones. En la implementación de la ruta /post/public/:id, se obtiene la ID de la publicación que se va a publicar de la URL y se pasa a la consulta update de Prisma Client. La implementación de la ruta /post/:id para eliminar una publicación de la base de datos también obtiene la ID de la publicación de la URL y la pasa a la consulta delete de Prisma Client.

      Vuelva a detener el servidor pulsando CTRL+C en el teclado. A continuación, reinicie el servidor utilizando lo siguiente:

      Puede probar la ruta PUT con el siguiente comando curl:

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

      Con esto, se publicará la publicación con un valor de ID de 2. Si reenvía la solicitud /feed, ahora, esta publicación se incluirá en la respuesta.

      Por último, puede probar la ruta DELETE con el siguiente comando curl:

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

      Con esto, se eliminará la publicación con un valor de ID de 1. Para confirmar que la publicación con esta ID se haya eliminado, puede reenviar una solicitud GET a la ruta /post/1.

      En este paso, implementó las rutas restantes de la API de REST para su aplicación de blog. Ahora, la API responde a diversas solicitudes GET, POST, PUT y DELETE e implementa la funcionalidad para leer y escribir datos en la base de datos.

      Conclusión

      En este artículo, creó un servidor para la API de REST con diversas rutas para crear, leer, actualizar y eliminar datos de usuarios y publicaciones para una aplicación de blog. Está utilizando Prisma Client dentro de las rutas de la API para enviar las consultas respectivas a su base de datos.

      Como próximo paso, puede implementar rutas de la API adicionales o ampliar el esquema de su base de datos utilizando Prisma Migrate. Asegúrese de consultar la documentación de Prisma para obtener más información sobre los distintos aspectos de Prisma y explorar algunos proyectos de ejemplo listos para ejecutar en el repositorio prisma-examples utilizando herramientas como GraphQL o API de grPC.



      Source link

      Comment développer une API REST avec Prisma et PostgreSQL


      L’auteur a choisi le Diversity in Tech Fund​​​​​ pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Prisma est une boîte à outils de base de données open source. Il se compose de trois outils principaux :

      • Prisma Client : un constructeur de requêtes automatisé de type sécurisé pour Node.js et TypeScript.
      • Prisma Migrate : un système déclaratif de modélisation et de migration de données.
      • Prisma Studio : une interface graphique permettant de visualiser et de modifier les données de votre base de données.

      Ces outils sont conçus pour optimiser la productivité d’un développeur d’applications dans les flux de travail de ses bases de données. L’un des principaux avantages de Prisma réside dans le niveau d’abstraction qu’il offre : Au lieu de trouver des requêtes SQL complexes ou des migrations de schéma, en utilisant Prisma, les développeurs d’applications peuvent travailler avec leur base de données en réfléchissant de manière plus intuitive sur leurs données.

      Dans ce tutoriel, vous allez créer une API REST pour une petite application de blogs dans TypeScript à l’aide de Prisma et d’une base de données PostgreSQL. Vous allez configurer votre base de données PostgreSQL localement avec Docker et implémenter des itinéraires API REST en utilisant Express. À la fin du tutoriel, vous disposerez d’un serveur web qui fonctionne localement sur votre machine, capable de répondre aux diverses demandes HTTP et de lire et écrire des données dans la base de données.

      Conditions préalables

      Ce tutoriel suppose que :

      Il vous sera utile d’avoir des connaissances de base sur les API TypeScript et REST, mais pas nécessaire pour suivre ce tutoriel.

      Étape 1 — Création de votre projet TypeScript

      Au cours de cette étape, vous allez configurer un projet TypeScript simple en utilisant npm. Ce projet constituera la base de l’API REST que vous allez développer tout au long de ce tutoriel.

      Tout d’abord, créez un nouveau répertoire pour votre projet :

      Ensuite, naviguez dans le répertoire et initialisez un projet npm vide. Notez que l’option -y signifie ici signifie que vous ignorez les invites interactives de la commande. Pour parcourir les invites, supprimez -y de la commande :

      Pour plus d’informations sur ces invites, vous pouvez suivre l’étape 1 dans Comment utiliser les modules Node.js avec npm et package.json.

      Vous obtiendrez un résultat similaire à ce qui suit, avec les réponses par défaut en 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" }

      Cette commande crée un fichier package.json minimal qui vous servira de fichier de configuration pour votre projet npm. Vous êtes maintenant prêt à configurer TypeScript dans votre projet.

      Exécutez la commande suivante pour procéder à une configuration simple de TypeScript :

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

      Vous installerez ainsi trois paquets en tant que dépendances de développement dans votre projet :

      • typescript : la chaîne d’outils TypeScript.
      • ts-node : un paquet qui exécutera les applications TypeScript sans compilation préalable à JavaScript.
      • @types/node : les définitions de type TypeScript pour Node.js.

      La dernière chose à faire consiste à ajouter un fichier tsconfig.json pour vous assurer que TypeScript est correctement configuré pour l’application que vous allez développer.

      Tout d’abord, exécutez la commande suivante pour créer le fichier :

      Ajoutez le code JSON suivant dans le fichier :

      my-blog/tsconfig.json

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

      Enregistrez et quittez le fichier.

      Il s’agit d’une configuration standard et minimale pour un projet TypeScript. Si vous souhaitez en savoir plus sur les propriétés individuelles du fichier de configuration, vous pouvez les consulter dans la documentation de TypeScript.

      Vous avez configuré votre projet TypeScript simple en utilisant npm. Ensuite, vous allez configurer votre base de données PostgreSQL avec Docker et y connecter Prisma.

      Étape 2 — Configuration de Prisma avec PostgreSQL

      Au cours de cette étape, vous allez installer la CLI Prisma, créer votre fichier de schéma Prisma, configurer PostgreSQL avec Docker et y connecter Prisma. Le schéma Prisma est le fichier de configuration principal de votre configuration Prisma et contient votre schéma de base de données.

      Commencez par installer la CLI Prisma avec la commande suivante :

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

      L’une des meilleures pratiques recommande d’installer la CLI Prisma localement dans votre projet (par opposition à une installation globale). Cela permet d’éviter les conflits de versions dans le cas où vous disposeriez de plusieurs projets Prisma sur votre machine.

      Ensuite, vous allez configurer votre base de données PostgreSQL en utilisant Docker. Créez un nouveau fichier Docker Compose avec la commande suivante :

      Maintenant, ajoutez le code suivant au fichier nouvellement créé :

      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:
      

      Ce fichier Docker Compose configure une base de données PostgreSQL qui peut être consultée via le port 5432 du conteneur Docker. Notez également que les informations d’identification de la base de données actuelles sont les suivantes : sammy (utilisateur) et your_password (mot de passe). N’hésitez pas à modifier ces informations d’identification et à utiliser votre nom d’utilisateur et votre mot de passe préférés. Enregistrez et quittez le fichier.

      Une fois cette configuration en place, vous pouvez lancer le serveur de base de données PostgreSQL avec la commande suivante :

      Le résultat de cette commande sera similaire à ce qui suit :

      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

      Vous pouvez vérifier si le serveur de base de données fonctionne avec la commande suivante :

      Vous obtiendrez un résultat similaire à celui-ci :

      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

      Maintenant que le serveur de la base de données est en cours d’exécution, vous pouvez créer votre configuration Prisma. Exécutez la commande suivante depuis la CLI Prisma :

      Vous obtiendrez le résultat suivant :

      Output

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

      Notez que l’une des meilleures pratiques vous recommande de préfixer toutes les invocations de CLI Prisma avec npx. Vous aurez ainsi la certitude que votre installation locale est bien utilisée.

      Une fois la commande exécutée, la CLI Prisma aura créé un nouveau dossier appelé prisma dans votre projet. Il contient les deux fichiers suivants :

      • schema.prisma : le fichier de configuration principal de votre projet Prisma (comprendra votre modèle de données).
      • .env : un fichier dotenv qui définit l’URL de connexion de votre base de données.

      Pour veiller à ce que Prisma connaisse bien l’emplacement de votre base de données, ouvrez le fichier .env et ajustez la variable de l’environnement DATABASE_URL.

      Tout d’abord, ouvrez le fichier .env :

      Maintenant, vous pouvez configurer la variable d’environnement de la manière suivante :

      my-blog/prisma/.env

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

      Veillez à bien remplacer les informations d’identification de la base de données par les données que vous avez spécifiées dans le fichier Docker Compose. Pour en savoir plus sur le format de l’URL de connexion, consultez les docs Prisma.

      Une fois que vous avez terminé, enregistrez et fermez le fichier.

      Au cours de cette étape, vous avez configuré votre base de données PostgreSQL avec Docker, installé la CLI Prisma et connecté Prisma à la base de données via une variable d’environnement. Lors de la section suivante, vous configurerez votre modèle de données et créerez les tableaux de votre base de données.

      Étape 3 — Configuration de votre modèle de données et création des tableaux de base de données

      Au cours de cette étape, vous allez configurer votre data model dans le fichier du schéma Prisma. Ce modèle de données sera ensuite mappé à la base de données avec Prisma Migrate, qui générera et enverra les instructions SQL pour créer les tableaux correspondant à votre modèle de données. Étant donné que vous développez une application de blog, les principales entités de l’application seront les utilisateurs et les publications.

      Prisma utilise son propre langage de modélisation des données pour définir la forme des données de votre application.

      Tout d’abord, ouvrez votre fichier schema.prisma avec la commande suivante :

      • nano prisma/schema.prisma

      Maintenant, ajoutez-y les définitions de modèles suivantes. Vous pouvez placer les modèles au bas du fichier, juste après le bloc 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-fr)
        authorId  Int?
      }
      

      Enregistrez et quittez le fichier.

      Vous allez définir deux modèles, que vous nommerez User et Post. Chacun de ces modèles possède un certain nombre de fields qui représentent les propriétés du modèle. Les modèles seront mappés sur les tables de base de données ; les champs représentent les colonnes individuelles.

      Notez également qu’il existe une relation de un à plusieurs entre les deux modèles, spécifiés par les champs de relation posts et author sur User et Post. Cela signifie qu’un utilisateur peut être associé à plusieurs publications.

      Une fois ces modèles en place, vous pouvez maintenant créer les tableaux correspondants dans la base de données en utilisant Prisma Migrate. Sur votre terminal, exécutez la commande suivante :

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

      Cette commande crée une nouvelle migration sur votre système de fichiers. Voici un aperçu rapide des trois options disponibles avec la commande :

      • --experimental : requise car Prisma Migrates indique actuellement un état experimental.
      • --create-db : permet à Prisma Migrate de créer la base de données nommée my-blog qui est spécifiée dans l’URL de connexion.
      • --name "init" : spécifie le nom de la migration (sera utilisé pour nommer le dossier de migration créé sur votre système de fichiers).

      Le résultat de cette commande sera similaire à ce qui suit :

      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-fr) authorId Int? } Prisma Migrate just created your migration 20200811140708-init in migrations/ └─ 20200811140708-init/ └─ steps.json └─ schema.prisma └─ README.md

      N’hésitez pas à explorer les fichiers de migration qui ont été créés dans le répertoire prisma/migrations.

      Pour exécuter la migration par rapport à votre base de données et créer les tableaux pour vos modèles Prisma, exécutez la commande suivante dans votre terminal :

      • npx prisma migrate up --experimental

      Vous obtiendrez le résultat suivant :

      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 génère maintenant les instructions SQL nécessaires à la migration et les envoie à la base de données. Les instructions SQL qui ont créé les tableaux sont les suivantes :

      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
      

      Au cours de cette étape, vous avez défini votre modèle de données dans votre schéma Prisma et créé les tableaux des bases de données correspondants avec Prisma Migrate. À l’étape suivante, vous allez installer Prisma Client dans votre projet afin de pouvoir interroger la base de données.

      Étape 4 — Exploration des requêtes Prisma Client dans un script simple

      Prisma Client est un constructeur de requêtes automatisé de type sécurisé qui vous permet de lire et d’écrire des données dans une base de données depuis une application Node.js ou TypeScript. Vous l’utiliserez pour accéder à la base de données dans vos itinéraires API REST, en remplaçant les ORM traditionnelles, les requêtes SQL simples, les couches d’accès aux données personnalisées ou toute autre méthode d’échange avec une base de données.

      Au cours de cette étape, vous allez installer Prisma Client et vous familiariser avec les requêtes que vous pouvez envoyer. Avant d’implémenter les itinéraires de votre API REST au cours des prochaines étapes, vous allez tout d’abord explorer certaines des requêtes Prisma Client dans un script exécutable simple.

      Premièrement, vous pouvez procéder à l’installation de Prisma Client dans votre projet en ouvrant votre terminal et en installant le paquet npm de Prisma Client :

      • npm install @prisma/client

      Ensuite, créez un nouveau répertoire que vous nommerez src. Il contiendra vos fichiers sources :

      Créez maintenant un fichier TypeScript à l’intérieur du nouveau répertoire :

      Toutes les requêtes de Prisma Client renvoient les promesses auxquelles vous pouvez vous attendre dans votre code. Vous devez donc envoyer les requêtes à l’intérieur d’une fonction async.

      Ajoutez le texte standard suivant avec une fonction async qui s’exécutera dans votre 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())
      

      Voici une rapide décomposition du texte standard :

      1. Importez le constructeur PrismaClient depuis le paquet @prisma/client npm déjà installé.
      2. Instanciez PrismaClient en appelant le constructeur et en obtenant une instance appelée prisma.
      3. Définissez une fonction async que vous appellerez main dans laquelle vous allez ensuite ajouter vos requêtes Prisma Client.
      4. Appelez la fonction main, tout en détectant toute exception potentielle et en vous assurant que Prisma Client ferme toutes les connexions à la base de données ouvertes, en appelant prisma.disconnect().

      Une fois la fonction main en place, vous pouvez commencer à ajouter les requêtes Prisma Client au script. Ajustez index.ts pour que cela ressemble à ce qui suit :

      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())
      

      Dans ce code, vous utilisez deux requêtes Prisma Client :

      • create : crée un nouvel enregistrement User. Notez que, en réalité, vous utilisez une écriture imbriquée, ce qui signifie que vous créez à la fois un enregistrement User et un enregistrement Post dans la même requête.
      • findMany : lit tous les enregistrements User existants depuis la base de données. Vous fournissez l’option include qui charge également les enregistrements de Post correspondants pour chaque enregistrement User.

      Maintenant, exécutez le script avec la commande suivante :

      Vous obtiendrez le résultat suivant dans votre 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 } ] }

      Remarque : si vous utilisez une interface graphique de base de données, vous pouvez valider si les données ont bien été créées en examinant les tableaux User et Post. Vous pouvez également explorer les données dans Prisma Studio en exécutant npx prisma studio --experimental.

      Vous avez maintenant utilisé Prisma Client pour lire et écrire des données dans votre base de données. Au cours des étapes restantes, vous allez appliquer ces nouvelles connaissances pour implémenter les itinéraires dans une API REST échantillon.

      Étape 5 — Implémentation de votre premier itinéraire API REST

      Au cours de cette étape, vous allez installer Express dans votre application. Express est un framework web populaire pour Node.js que vous utiliserez pour implémenter vos itinéraires API REST dans ce projet. Le premier itinéraire que vous allez implémenter vous permettra de récupérer tous les utilisateurs de l’API en utilisant une requête GET. Les données utilisateur seront récupérées depuis la base de données en utilisant Prisma Client.

      Vous pouvez maintenant installer Express avec la commande suivante :

      Étant donné que vous utilisez TypeScript, vous devez également installer les types correspondants en tant que dépendances de développement. Pour cela, exécutez la commande suivante :

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

      Une fois les dépendances installée, vous pouvez configurer votre application Express.

      Commencez par rouvrir votre fichier source principal :

      Maintenant, supprimez l’intégralité du code dans index.ts et remplacez-le par ce qui suit pour lancer votre API REST :

      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'),
      )
      

      Voici une décomposition rapide du code :

      1. Importez PrismaClient et express à partir des paquets npm correspondants.
      2. Instanciez PrismaClient en appelant le constructeur et en obtenant une instance appelée prisma.
      3. Créez votre application Express en appelant express().
      4. Ajoutez le logiciel médiateur express.json() pour avoir la certitude que les données de JSON soient correctement traitées par Express.
      5. Lancez le serveur sur le port 3000.

      Maintenant, vous pouvez implémenter votre premier itinéraire. Entre les appels à app.use et app.listen, ajoutez le code suivant :

      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'),
      )
      

      Une fois ajouté, enregistrez et fermez votre fichier. Ensuite, démarrez votre serveur web local en utilisant la commande suivante :

      Vous recevrez le résultat suivant :

      Output

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

      Pour accéder à l’itinéraire /users, vous pouvez pointer votre navigateur vers http://localhost:3000/users ou tout autre client HTTP.

      Dans ce tutoriel, vous allez tester tous les itinéraire API REST en utilisant curl, un client HTTP basé sur le terminal.

      Note : si vous préférez utiliser un client HTTP basé sur une interface graphique, vous pouvez utiliser des alternatives comme Postwoman ou le Advanced REST Client.

      Pour tester votre itinéraire, ouvrez une nouvelle fenêtre ou un nouveal onglet du terminal (afin que votre serveur web local puisse continuer à fonctionner) et exécutez la commande suivante :

      • curl http://localhost:3000/users

      Vous obtiendrez les données User que vous avez créées au cours de l’étape précédente : 

      Output

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

      Notez que, cette fois, le tableau posts n’est pas inclus, étant donné que vous ne faites pas passer l’option include à l’appel findMany dans l’implémentation de l’itinéraire /users.

      Vous avez implémenté votre premier itinéraire API REST au niveau de /users. Au cours de l’étape suivante, vous allez implémenter les autres itinéraires API REST pour ajouter plus de fonctionnalités à votre API.

      Étape 6 — Implémentation des itinéraires API REST restants

      Au cours de cette étape, vous allez implémenter les autres itinéraires API REST de votre application de blog. À la fin, votre serveur web servira diverses requêtes GET, POST, PUT et DELETE.

      Voici un aperçu des différents itinéraires que vous allez implémenter :

      Méthode HTTP Itinéraire Description
      GET /feed Récupère toutes les publications published.
      GET /post/:id Récupère une publication spécifique en utilisant son ID.
      POST /user Crée un nouvel utilisateur.
      POST /post Crée une nouvelle publication (en tant que draft).
      PUT /post/publish/:id Définit le champ published d’une publication comme true.
      DELETE post/:id Supprime une publication en utilisant son ID.

      Vous pouvez maintenant implémenter le reste des itinéraires Get en premier.

      Ouvrez la commande index.ts avec la commande suivante :

      Ensuite, ajoutez le code suivant une fois l’itinéraire /users  implémenté :

      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'),
      )
      

      Enregistrez et fermez votre fichier

      Ce code implémente les itinéraires API pour deux requêtes GET :

      • /feed : renvoie une liste des posts publiés.
      • /post/:id : renvoie un post spécifique en utilisant son ID.

      Prisma Client est utilisé dans les deux implémentations. Dans l’implémentation de l’itinéraire /feed, la requête que vous envoyez avec Prisma Client filtre pour tous les enregistrements Post pour lesquels la colonne published indique la valeur true. En outre, la requête Prisma Client utilise include pour récupérer les informations liées à l’author pour chaque publication renvoyée. Dans l’implémentation de l’itinéraire /post/:id, faites passer l’ID récupérée depuis le chemin de l’URL afin de lire un enregistrement Post spécifique depuis la base de données.

      Vous pouvez arrêter le serveur en utilisant les touches CTRL+C de votre clavier. Ensuite, redémarrez le serveur en utilisant :

      Pour tester l’itinéraire /feed, vous pouvez utiliser la commande curl suivante :

      • curl http://localhost:3000/feed

      Étant donné qu’aucune publication n’a encore été publiée, la réponse prendra la forme d’un tableau vide :

      Output

      []

      Pour tester l’itinéraire /post/:id, vous pouvez utiliser la commande curl suivante :

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

      Vous obtiendrez la publication que vous avez créée initialement :

      Output

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

      Ensuite, implémentez les deux itinéraires POST. Ajoutez le code suivant à index.ts après les trois itinéraires 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'),
      )
      

      Une fois que vous avez terminé, enregistrez et fermez le fichier.

      Ce code implémente les itinéraires API pour deux requêtes POST :

      • /user : crée un nouvel utilisateur dans la base de données.
      • /post : crée une nouvelle publication dans la base de données.

      Comme auparavant, Prisma Client est utilisé dans les deux implémentations. Dans le cadre de l’implémentation de l’itinéraire /user, vous faites passer les valeurs depuis le corps de la requête HTTP à la requête create de Prisma Client.

      L’itinéraire /post exige un peu plus d’implication. Ici, vous ne pouvez pas faire passer les valeurs directement depuis le corps de la requête HTTP. Au contraire, vous devez d’abord les extraire manuellement afin de les transmettre à la requête Prisma Client. En effet, étant donné que la structure de JSON dans le corps de requête ne correspond pas à la structure attendue par Prisma Client. Vous devez donc créer la structure attendue manuellement.

      Vous pouvez tester les nouveaux itinéraires en arrêtant le serveur avec CTRL+C. Ensuite, redémarrez le serveur en utilisant :

      Pour créer un nouvel utilisateur via l’itinéraire /user, vous pouvez envoyer la requête POST suivante avec curl :

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

      Cela créera un nouvel utilisateur dans la base de données, en donnant le résultat suivant :

      Output

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

      Pour créer une nouvelle publication via l’itinéraire /post, vous pouvez envoyer la requête POST suivante avec curl :

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

      Cela créera une nouvelle publication dans la base de données et la connectera à l’utilisateur avec le courriel bob@prisma.io. Cela donne le résultat suivant :

      Output

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

      Enfin, vous pouvez implémenter les itinéraires PUT et DELETE.

      Ouvrez la commande index.ts avec la commande suivante :

      Ensuite, une fois les deux itinéraires POST implémentés, ajoutez le code surligné :

      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'),
      )
      

      Enregistrez et fermez votre fichier

      Ce code implémente les itinéraires API pour une requête PUT et une requête DELETE :

      • /post/publish/:id (PUT) : publie une publication en utilisant son ID.
      • /post/:id (DELETE) : supprime une publication en utilisant son ID.

      À nouveau, Prisma Client est utilisé dans les deux implémentations. Dans le cadre de l’implémentation de l’itinéraire /post/publish/:id, l’ID du message à publier est récupéré depuis l’URL et transmis à la requête update de Prisma Client. L’implémentation de l’itinéraire /post/:id qui permet de supprimer une publication dans la base de données renvoie également l’ID de l’URL et le transmet à la requête delete de Prisma Client.

      Encore une fois, arrêtez le serveur à l’aide des touches CTRL+C de votre clavier. Ensuite, redémarrez le serveur en utilisant :

      Vous pouvez tester l’itinéraire PUT avec la commande curl suivante :

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

      Cela vous permettra de publier la publication avec une valeur d’ID de 2. Si vous renvoyez la requête /feed, cette publication sera alors incluse dans la réponse.

      Enfin, vous pouvez tester l’itinéraire DELETE avec la commande curl suivante :

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

      Cela vous permettra de supprimer la publication avec une valeur d’ID de 1. Pour valider le fait que la publication portant cet ID ait été supprimée, vous pouvez renvoyer une requête GET à l’itinéraire /post/1.

      Au cours de cette étape, vous avez implémenté les autres itinéraires API REST de votre application de blog. L’API répond maintenant aux diverses requêtes GET, POST, PUT et DELETE et implémente une fonctionnalité pour lire et écrire des données dans la base de données.

      Conclusion

      Au cours de cet article, vous avez créé un serveur API REST avec plusieurs itinéraires différents pour créer, lire, mettre à jour et supprimer les données utilisateur et de publications pour une application de blog échantillon. À l’intérieur des itinéraires de l’API, vous utilisez le Prisma Client pour envoyer les requêtes correspondantes à votre base de données.

      Ensuite, vous pouvez implémenter des itinéraires API supplémentaires ou étendre le schéma de votre base de données en utilisant Prisma Migrate. Veillez à consulter la documentation de Prisma pour en savoir plus sur les divers aspects de Prisma et à explorer quelques exemples de projets prêts à l’exécution dans le référentiel prisma-examples – en utilisant des outils comme les API GraphQL ou grPC.



      Source link