Master Deno.js: Build a Full‑Stack MySQL CRUD API

This tutorial introduces Deno.js, explains its security‑first runtime features, compares it with Node.js, and walks through building a complete MySQL‑backed CRUD REST API using TypeScript, covering installation, code structure, and execution steps.

21CTO
21CTO
21CTO
Master Deno.js: Build a Full‑Stack MySQL CRUD API

Introduction

Just as dinosaurs once ruled the Earth, Deno.js returns to the modern digital era as a secure, modern runtime for JavaScript and TypeScript.

What Is Deno.js?

Deno.js (official site: https://deno.land) is a JavaScript/TypeScript runtime built on the V8 engine, written in Rust and Tokio. It was created by Ryan Dahl, the original founder of Node.js, and launched in 2018.

Its goals are to provide developers with an efficient, secure scripting environment that can replace traditional Bash or Python shell scripts.

Key Features of Deno.js

Secure by default – no network or file‑system access unless explicitly granted (e.g., deno run --allow-write file.ts).

One‑line installation: curl -fsSL https://deno.land/x/install/install.sh | sh.

Runs entire projects with a single command.

Decentralized dependency storage via URLs, eliminating the need for package.json and node_modules.

Native support for both JavaScript and TypeScript without external compilers.

Compatible with browser APIs and does not require bundlers like Webpack or Babel.

Comparison with Node.js

Because Deno was designed by Node’s creator, the differences are clear:

No npm registry – dependencies are fetched directly from URLs.

Explicit permission flags are required for file, network, or environment access.

All asynchronous operations return Promise, changing request handling patterns.

Errors must be handled explicitly; uncaught exceptions halt execution.

Future Challenges

Despite its advantages, Deno faces hurdles before widespread adoption:

Lack of a package.json means developers must manage imports manually or use import maps.

Versioning of dependencies via URLs can be cumbersome.

Enterprise ecosystems built around Node.js are not yet fully compatible with Deno.

Deno.js CRUD with MySQL – Complete Example

The following project demonstrates a full CRUD REST API using Deno, TypeScript, and MySQL. The domain model is an Employee with id, name, department, and isActive fields.

Configuration (server.ts)

const app = new Application();
const port: number = 8080;
app.use(logger.logger);
app.use(logger.responseTime);
app.use(employeeRouter.routes());
app.use(employeeRouter.allowedMethods());
app.addEventListener("listen", ({ secure, hostname, port }) => {
  const protocol = secure ? "https://" : "http://";
  const url = `${protocol}${hostname ?? "localhost"}:${port}`;
  console.log(`${yellow("Listening on:")} ${green(url)}`);
});
await app.listen({ port });

Model (Employee.ts)

export default interface Employee {
  id?: number,
  name?: string,
  department?: string,
  isActive?: boolean
}

Database Client (client.ts)

const client = await new Client();
client.connect({
  hostname: "127.0.0.1",
  username: "your db username",
  password: "your db password",
  db: "",
});
const run = async () => {
  await client.execute(`CREATE DATABASE IF NOT EXISTS ${DATABASE}`);
  await client.execute(`USE ${DATABASE}`);
};
run();
export default client;

Service Layer (employeeService.ts)

export default {
  doesExistById: async ({ id }: Employee) => {
    const [result] = await client.query(`SELECT COUNT(*) count FROM ${TABLE.EMPLOYEE} WHERE id = ? LIMIT 1`, [id]);
    return result.count > 0;
  },
  getAll: async () => await client.query(`SELECT * FROM ${TABLE.EMPLOYEE}`),
  getById: async ({ id }: Employee) => await client.query(`SELECT * FROM ${TABLE.EMPLOYEE} WHERE id = ?`, [id]),
  add: async ({ name, department, isActive }: Employee) => await client.query(`INSERT INTO ${TABLE.EMPLOYEE}(name, department, isActive) values(?, ?, ?)`, [name, department, isActive]),
  updateById: async ({ id, name, department, isActive }: Employee) => {
    const result = await client.query(`UPDATE ${TABLE.EMPLOYEE} SET name=?, department=?, isActive=? WHERE id=?`, [name, department, isActive, id]);
    return result.affectedRows;
  },
  deleteById: async ({ id }: Employee) => {
    const result = await client.query(`DELETE FROM ${TABLE.EMPLOYEE} WHERE id = ?`, [id]);
    return result.affectedRows;
  }
};

Controller Layer (employeeController.ts)

// GET all
getAllEmployees: async ({ response }) => {
  const data = await EmployeeService.getAll();
  response.status = 200;
  response.body = { success: true, data };
},
// POST create
createEmployee: async ({ request, response }) => {
  const body = await request.body();
  await EmployeeService.add({ name: body.value.name, department: body.value.department, isActive: true });
  response.body = { success: true, message: "The record was added successfully" };
},
// GET by ID
getEmployeeById: async ({ params, response }) => {
  const employee = await EmployeeService.getById({ id: Number(params.id) });
  response.status = 200;
  response.body = { success: true, data: employee };
},
// PUT update
updateEmployeeById: async ({ params, request, response }) => {
  const body = await request.body();
  const updatedRows = await EmployeeService.updateById({ id: Number(params.id), ...body.value });
  response.body = { success: true, affected: updatedRows };
},
// DELETE
deleteEmployeeById: async ({ params, response }) => {
  const affected = await EmployeeService.deleteById({ id: Number(params.id) });
  response.body = { success: true, affected };
};

Routing (employee.route.js)

const router = new Router();
router
  .get("/employee", employeeController.getAllEmployees)
  .post("/employee", employeeController.createEmployee)
  .get("/employee/:id", employeeController.getEmployeeById)
  .put("/employee/:id", employeeController.updateEmployeeById)
  .delete("/employee/:id", employeeController.deleteEmployeeById);
export default router;

Running the Application

deno run --allow-env --allow-net server.ts

The server starts at http://localhost:8080. You can test the endpoints with tools like Postman; screenshots of the employee list, updates, and deletions are shown below.

Conclusion

This tutorial demonstrated how to use Deno.js to build a complete CRUD REST API backed by MySQL, highlighting its security model, dependency handling, and TypeScript support. For the full project source, readers can request the code from the original publisher.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendTypeScriptJavaScriptmysqlREST APICRUDDeno
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.