SvelteKit & Prisma - A match made in digital heaven

Mike - Aug 3 '21 - - Dev Community

Key Takeaways

  • Most production applications need to persist & retrieve data. Prisma is a pretty genius way to achieve that.
  • With SvelteKit, you get client & server-side data fetching - the best of both worlds.
  • This all even works if JavaScript is disabled in the browser.
  • Template GitHub repo: https://github.com/mikenikles/sveltekit-prisma

What are you going to learn?

We are going to start with a default SvelteKit application. Once initialized, we will learn how to install and configure Prisma before we will use the PrismaClient to perform create, read, update & delete (CRUD) actions against a local SQLite database.

Things you need to know

In order to get the most out of this post, I expect you are aware of the following technologies:

The foundation

Let's start with the basics: A SvelteKit demo app.

I recommend you first create a GitHub, GitLab or Bitbucket project and start a development environment with Gitpod. Alternatively, you can follow along on your local computer.

npm init svelte@next svelte-with-prisma
Enter fullscreen mode Exit fullscreen mode

When prompted, select the following options:

  • "Which Svelte app template?" SvelteKit demo app
  • "Use TypeScript?" Yes
  • "Add ESLint for code linting?" No
  • "Add Prettier for code formatting?" Yes

When complete, please follow the "Next steps" listed in the terminal to install dependencies and start the SvelteKit demo app.

If you've followed along so far, you can copy & paste the following commands:

cd svelte-with-prisma
npm install
npm run dev -- --open
Enter fullscreen mode Exit fullscreen mode

That's how quickly you get started with SvelteKit. In your browser, you notice the "TODOS" navigation item. If you play with this list, items are persisted on svelte.dev and deleted after a while.

Next, we are going to add Prisma to persist todo items in a local SQLite database.

Add Prisma

Prisma.io states "Prisma helps app developers build faster and make fewer errors with an open source ORM for PostgreSQL, MySQL and SQLite."

From my personal experience, this statement is certainly true. Let's go and experience it for yourself.

Install & initialize Prisma

First things first: npm i -D prisma because, well... without dependencies we won't get very far 😉.

Next, we are going to initialize Prisma. For that, we use npx to execute commands.

npx prisma init
Enter fullscreen mode Exit fullscreen mode

⚠️ This currently overwrites an existing .gitignore file. Keep an eye on 8496.

This creates a prisma directory at the root of the project. In it, you find the schema.prisma file.

At this point, I recommend you install the prisma.prisma VS Code extension. It adds syntax highlighting, formatting, auto-completion, jump-to-definition and linting for .prisma files.

Define the Todo model

Open the prisma/schema.prisma file and add the following model definition to the end of the file:

model Todo {
  uid        String  @id @default(cuid())
  created_at DateTime
  text       String
  done       Boolean
}
Enter fullscreen mode Exit fullscreen mode

Psst... How do we know what fields to define? Well, we take a peek at the Todo type definition in src/routes/todos/index.svelte 😉.

Configure a SQLite database

Open the .env file (that file was created by the npx prisma init command earlier). In it, set the DATABASE_URL to "file:./dev.db"

We also have to open the prisma/schema.prisma file to update the datasource.db.provider to sqlite.

Check the reference docs for more details on the above two values and what other databases are supported.

Create the database and tables

We're making great progress! Let's now use the Prisma CLI to create our SQLite database and create a schema based on the Todo model we defined earlier.

It's easy:

npx prisma db push
Enter fullscreen mode Exit fullscreen mode

Give that five seconds ⏳.

I recommend you read through the console output, I find it highly interesting. For one, it gives us a good deal of detail about what's going on. However, it also contains the following output which is one of the reasons I'm mind-blown by Prisma:

✔ Generated Prisma Client (2.28.0) to ./node_modules/@prisma/client
Enter fullscreen mode Exit fullscreen mode

So much goodness! Basically, they use the Todo model to auto-generate a bunch of TypeScript definitions and Javascript code which we are going to import in just a second. In other words, the "Prisma helps app developers build faster and make fewer errors" sentence on the Prisma website is not just some marketing speech, it is truly genius!

Ok, I'm done being a fanboy about it, let's move on and thanks for your patience there with me 😅.

One last thing, please add prisma/dev.db to your .gitignore file since we don't want to commit the dev database to version control.

Use the PrismaClient to interact with the database

The SvelteKit demo app nicely encapsulates all API features in the src/routes/todos/_api.ts file. To be more precise, the actual CRUD logic happens at https://api.svelte.dev/todos. We are going to modify the _api.ts file slightly to deal with CRUD right there and use the PrismaClient instead of delegating to a backend API.

Move the Todo type so we can reuse it

First and foremost, let's move the Todo Typescript type. By default, it's defined and used in the src/routes/todos/index.svelte file. However, with the changes we're going to make to the API, we are also going to need that type in the src/routes/todos/_api.ts file.

  1. Cut the Todo type from src/routes/todos/index.svelte
  2. Paste it below the import statements in src/routes/todos/_api.ts, and prefix it with export
  3. Use the following import in the src/routes/todos/index.svelte file: import type { Todo } from "./_api";

Update the API to use Prisma

Open the src/routes/todos/_api.ts file and add the following import:

import { PrismaClient } from '@prisma/client';
Enter fullscreen mode Exit fullscreen mode

Remember? That's the generated code I was so excited about earlier 😀.

Next, we need a new instance of the PrismaClient (add this below the import statements):

const prisma = new PrismaClient();
Enter fullscreen mode Exit fullscreen mode

Moving right along, it's time to update the api method signature to tell Typescript that the data parameter is of type Todo.

export async function api(request: Request<Locals>, resource: string, data?: Todo) {
Enter fullscreen mode Exit fullscreen mode

The following code:

const res = await fetch(`${base}/${resource}`, {
  method: request.method,
  headers: {
    'content-type': 'application/json'
  },
  body: data && JSON.stringify(data)
});
Enter fullscreen mode Exit fullscreen mode

needs to be replaced with this:

let body = {};
let status = 500;
switch (request.method.toUpperCase()) {
  case "DELETE":
    await prisma.todo.delete({
      where: {
        uid: resource.split("/").pop()
      }
    });
    status = 200;
    break;
  case "GET":
    body = await prisma.todo.findMany();
    status = 200;
    break;
  case "PATCH":
    body = await prisma.todo.update({
      data: {
        done: data.done,
        text: data.text
      },
      where: {
        uid: resource.split("/").pop()
      }
    });
    status = 200;
    break;
  case "POST":
    body = await prisma.todo.create({
      data: {
        created_at: new Date(),
        done: false,
        text: data.text,
      }
    });
    status = 201;
    break;
}
Enter fullscreen mode Exit fullscreen mode

We're getting there 💪. In the if statement right below the code we've just added, remove the res.ok && since we no longer have a res variable.

Lastly, change the return statement to the following:

return {
  status,
  body
};
Enter fullscreen mode Exit fullscreen mode

Let's test

Start your SvelteKit demo app with npm run dev and navigate to http://localhost:3000 in your browser. If you use Gitpod, hold CTRL / CMD pressed and click on the http://localhost:3000 URL in the terminal, it'll open a new browser window with the SvelteKit demo app.

Click on the "TODOS" navigation link and add a few todos, rename some, mark others as done.

In a new terminal, open the Prisma Studio with npx prisma studio. The studio opens in a new browser tab. Click on the Todo model and validate that the data matches what you see in the SvelteKit demo app.

Congratulations 🎉!

Bonus - definitely read this

Disable JavaScript in your browser and test the todo list again. This is how the web is supposed to work - without JavaScript!

We used to develop websites like that, then we spent a decade thinking it's a great idea to move everything into JavaScript and thanks to Svelte & SvelteKit, we now once again develop web applications that work the way the web was intended to work.

JavaScript's purpose is to enhance the web experience, not break everything if JavaScript is disabled.

Conclusion

With a few modifications to a default SvelteKit demo app, we managed to configure Prisma to persist todo items. There is of course a lot more you can do with Prisma, and with SvelteKit for that matter. The source code at https://github.com/mikenikles/sveltekit-prisma should get you a long way towards your own web app.

If you found this interesting, you may also like (wow... is this an e-commerce website 😂?!) my current project called Webstone. Webstone is a full-stack web application boilerplate with a CLI to automate tedious tasks like adding new pages, updating the database (of course it uses Prisma 😉). It's in early development, but do hit that star button on GitHub which helps me get motivated to spend more time on the project 🙏.

👋

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .