Nitro Server with Nuxt3

Nishant Aanjaney Jalan
CodeX
Published in
5 min readMay 14, 2022
Nuxt3 Nitro

NO — this is not a tutorial for cloning Discord Nitro on Nuxt3 😜. Although that would be a great project to do someday 🤔. In this article, we are going to write some backend server code on Nuxt3.

Whaaaatttttttt?😱 But isn’t Nuxt3 a front-end framework? How and why will I write my backend code on my front-end?

To create a full-stack application, we need a server-side code and a client-side code. The traditional frameworks bundle their code, and this file is sent whenever the user makes a GET '/' request on your server. We could have a Flask backend with a Svelte frontend to do this. Problems might arise while trying to bridge the two technologies together.

What if I tell you that we can do this on the same codebase?

Yes — Nuxt3 introduces the Nitro server where you can write your server-side code in your project and deploy it too!

Getting Started

Like any other feature that Nuxt3 provides out-of-the-box, we need to create a server/ directory in the root folder of your project. Any code inside this will be rendered by the Nitro server for the backend. Let us create 4 different routes that will illustrate every concept required to know the basics of Nitro.

1. GET '/api/users/’— this route will fetch all the users we have registered with us.

2. POST '/api/users/' — this route will create a new user with the username.

3. PUT '/api/users/{id}' — this route will change the online status of the user.

4. DELETE '/api/users/{id}' — this route will, no brainer, delete the user.

Creating our fake DB

We won’t be dealing with any local or cloud database here, so let’s create a folder inside the server/ directory db/ and a TypeScript file called index.ts

server/db/index.ts

Creating our server routes

Based on the 4 routes listed above, we have to create a structure that resembles it. In Nuxt3 projects, it is very important to maintain the directory structure.

|- server/
| |- api/
| | |- users/
| | | |- [id].ts
| | | |- index.ts
| |- db/
| | |- index.ts
|- app.vue
|- nuxt.config.ts
|- package.json
|- package-lock.json
|- README.md
|- tsconfig.json

The db/ route is for the fake database that we have. The other folders are slightly self-explanatory. The server/api/users/index.ts calls any route associated with /api/users while server/api/users/[id].ts is used where is a path parameter /api/users/{id}.

#1 — GET ‘/api/users’

For the 1st route, we place our code in the /api/users/index.ts file because it does not accept any path parameters. We have to default export a function named defineEventHandler which would handle any incoming route based on the directory structure. We have an anonymous function with the event passed down as the parameter. This event parameter contains all the required details about the incoming request.

server/api/users/index.ts

e.req.method fetches the name of the incoming HTTP method and we can act according i.e. to return the users.

#2 — POST ‘/api/users/’

Now, since the URL of the request is the same, we will be working on the same index.ts file route.

Prerequisite: you need to run the following command:

npm i uuid @types/uuid.

server/api/users/index.ts

If the incoming request for that URL is a POST request, we can extract the body by awaiting with the useBody() function where we pass the event object. The rest of the code is self-explanatory. The username property is asserted, pushed to our mock database and returned the user object. Note the code for sending the error.

#3 — PUT ‘/api/users/{id}’

This requires a path parameter and hence goes to the [id].ts file. We can start by creating a function that would try and find the user from the database and return the object along with the index of that object in the array. If the user is not found by the ID, we can simply throw a 404 HTTP error.

server/api/users/[id].ts

This time, I can use a switch case instead of two ifs to write my code.

server/api/users/[id].ts

If the incoming request is a PUT method, I am extracting the ID from the event object by using e.context.params. With this specific ID, I am searching for the user from the database with the function we wrote above. The user object returned to us will never be null or undefined. We change the value of the online status and return the updated user object.

#4 — DELETE ‘/api/users/{id}’

In the same file, under the case "DELETE", we can code the logic for deleting the user from the mock database.

server/api/users/[id].ts

Based on what we have done before, this code is too self-explanatory. We find the index of the required user and splice it from the array in the db object.

AND WE ARE DONE WITH OUR SERVER CODE! 🎉

How to use this on the front-end? Simple — we can use useFetch('/api/users') or $fetch('/api/users') on your front-end to make server requests to these routes.

Conclusion

Having the server code and client code on the same codebases minimizes any effort to bridge the two together and eliminates any problems that may arise as Nuxt3 bundles the server along during deployment. The directory structure provides a very systematic approach and is very easy to read and understand working as a team.

Follow my Nuxt3 Tutorial List to master the basics of using Nuxt3. Thank you, and I hope you enjoyed and learnt something. ✌️

Nuxt3 Tutorial

8 stories

--

--

Nishant Aanjaney Jalan
CodeX
Editor for

Undergraduate Student | CS and Math Teacher | Android & Full-Stack Developer | Oracle Certified Java Programmer | https://cybercoder-naj.github.io