Read Data from a DB model in Blitzjs

Khaled Garbaya
InstructorKhaled Garbaya

Share this video with your friends

Send Tweet
Published a year ago
Updated 10 months ago

In a classic App to read from the database, you need some code to run on a server layer somewhere and share the data via REST with your client code. Blitz makes this process a lot easier using queries.

Blitz queries are plain, asynchronous JavaScript functions that always run on the server. Instead of calling an endpoint Blitz will allow you to import that code directly into your front end code so you don't need to build an API and do data fetching from the frontend. At build time, Blitz automatically inserts an API call that runs the server code on the server. Essentially, Blitz abstracts your API into a compile step.

Queries must be inside queries folder

Example:

  • app/queries/getPost.ts
  • app/posts/queries/getPost
  • app/admin/posts/queries/getPost

To read from the database you can use the db package e.g db.{modelName}.findOne.

To a single post, your query should look like this

import { NotFoundError } from "blitz"
import db, { FindOnePostArgs } from "db"

type GetPostInput = {
  where: FindOnePostArgs["where"]
}

export default async function getPost({ where }: GetPostInput) {
  const post = await db.post.findOne({ where })
  if (!post) throw NotFoundError
  return post
}

Another cool thing with Blitz is that React Concurrent Mode is enabled by default. So the <Suspense> component is used for loading states and <ErrorBoundary> is used to display errors. If you need, you can read the React Concurrent Mode Docs.

In order to use a query on your React component, you need to wrap them in <Suspense>.

Example:

import { useParams, useQuery } from "blitz"
import getPost from "../../posts/queries/getPost"
import { Suspense } from "react"

const Post = () => {
  const params = useParams()
  const [post] = useQuery(getPost, { where: { slug: params.slug as string } })
  return (
    <div>
      <h1>Post: {post.title}</h1>
    </div>
  )
}

const PostPage = () => {
  return (
    <Suspense fallback={<span>Loading...</span>}>
      <Post />
    </Suspense>
  )
}

export default PostPage

Khaled Garbaya: [0:00] To be able to pull data from the database into our Blitz app, we need to create a query. Let's go back to our project. Inside of app, let's create a new folder, call it posts. Inside of posts, we can create another folder, call it queries.

[0:16] Here, we'll have our first query which is getPost. It's going be new file, and then we call it getPost.ts. We need to do a few imports here. One is the NotFoundError. Then, we need to import the db and FindOnePostArgs.

[0:33] Let's define our post input. These will be the parameters that we will pass from our page to this query to be able to query for a post. Lastly, we need to export the function getPost to be used inside of our page, so we can do export default. It's going to be async function, and we call it getPost. This will accept the post input.

[1:03] We're going to extract the where parameters from it. Once we receive the where parameter, we can query our database for our post. We're going to do const post and we await the db.post.findOne. Here, we will pass in our where argument. Let's do a check. If the post does not exist, we will throw an error. Here we can throw the NotFoundError. Otherwise, we will return our post.

[1:33] Let's hit Save and let's go back to our post page. This is inside of pages, posts, and then slug. Now, let's import our getPost query and here let's get our post. Before doing that, let's import useQuery.

[1:49] Then, I have our post=useQuery, and then we can pass in the function getPost. This is used by Blitz to also do some caching. Let's call useQuery. Here, we'll pass in the function, which is getPost and also the arguments.

[2:07] We're going to call the where and then pass in the slug from the parameter that we've been using before. Here, this is going to be params.slug. Instead of displaying the params.slug, we can do post and then title.

[2:26] That's not enough. We need to wrap this post component with a Suspense component. Let's import { Suspense } from "react", and then here, let's have const PostPage. This will be our Wrapper component. Here, we will return Suspense and the fallback for now will be a small span.

[2:51] Here, it's going to be span. We can do "Loading..." Inside of that now we can add our Post component. We will need to change this export default from Post now to PostPage. Let's hit Save. Let's run our server. I'll need to close the Studio also.

[3:09] If we refresh this page, it should show the post title. I have an error here, and that's probably because I was using the wrong slug. Because if we do id 1 in here and then hit Save, it will return our first post.

[3:29] If we check the slug here, it's "Hello, World," so it was mistyped from my side. If we go back here to slug, and in the URL, we can add in the correct slug and hit Enter. You can see here we have our post.