Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The first app

A Hono app is an object created with new Hono(). You add routes to it and then pass its app.fetch function to a server. On Node.js the server is started by the serve() function from the @hono/node-server package.

The entry file

Right after creating the project, src/index.ts looks like this:

// src/index.ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
 
const app = new Hono()
 
app.get('/', (c) => {
  return c.text('Hello Hono!')
})
 
serve({
  fetch: app.fetch,
  port: 3000,
}, (info) => {
  console.log(`Server is running on http://localhost:${info.port}`)
})

Piece by piece:

LineWhat it does
new Hono()creates the app
app.get('/', ...)adds a route for a GET request to /
cthe context — an object with the request and methods for the response
c.text(...)creates a plain-text response
serve(...)starts a Node.js HTTP server and passes every request to app.fetch

The second argument of serve() is called when the server is ready and prints the address to the terminal.

The first JSON

Hono is most often used for APIs, so add a route that returns the list of blog posts:

// src/index.ts
const posts = [
  { id: 1, title: 'First post', body: 'Hello, world!' },
  { id: 2, title: 'Second post', body: 'Learning Hono.' },
]
 
app.get('/posts', (c) => {
  return c.json(posts)
})

Put this code before the serve() call. The c.json() method turns the array into a JSON string and sets the Content-Type: application/json header itself. Open http://localhost:3000/posts and the browser shows an array of two posts.

A request from the terminal

APIs are handy to check with curl:

curl http://localhost:3000/posts

The terminal prints the same JSON. The -i flag also shows the response headers:

curl -i http://localhost:3000/posts

The first line of the response is HTTP/1.1 200 OK, and the headers include content-type: application/json.

Restart on changes

npm run dev watches your files. Change the text in c.text(), save the file and refresh the page — the new text appears without a manual restart.

Port

The port is set in serve(). To change it without editing the code, read it from an environment variable:

// src/index.ts
const port = Number(process.env.PORT ?? 3000)
 
serve({ fetch: app.fetch, port })

Environment variables get their own lesson later.

Common mistake

Running npm run dev a second time in another terminal while the first one is still running. The second process crashes with EADDRINUSE: port 3000 is already taken. The server should run as a single instance — stop the extra one with Ctrl+C or set a different port.

Thanks for reading!

Donate to the site — we work hard for you.