REST
Introducción
Section titled “Introducción”Un servidor web se puede configurar como un servidor de recursos que se accede mediante un conjunto de funciones “externas” o endpoints (API)
REST (Representational State Transfer) es una forma bastante habitual de interacción entre aplicaciones y servicios de cliente mediante HTTP.
Una solicitud HTTP se compone de un método y un “path”.
Por defecto, los navegadores utilizan el método GET
, y cuando navegas a un sitio web lo haces con una petición GET
y sólo tienes que indicar el “path”.
Pero una API web utiliza otros métodos, y los clientes utilizan esos métodos para realizar otras acciones que no són obtener recursos.
En este enlace tienes un proyecto de ayuda https://gitlab.com/xtec/typescript/hono (TODO Move a rest)
Entorno de trabajo
Section titled “Entorno de trabajo”Crea una aplicación (con el template cloudflare-workers
)
> bun create hono@latest hono...✔ Which template do you want to use? cloudflare-workers
Ejecuta el servidor en modo desarrollo:
> bun run dev...⎔ Starting local server...[wrangler:inf] Ready on http://127.0.0.1:8787...
Modifica el fichero index.ts
para que devuelva un documento JSON en el path /api/hello
:
import { Hono } from 'hono'
const app = new Hono()
app.get('/api/hello', (c) => { return c.json({ ok: true, message: 'Hello Hono!', })})
export default app
Instala curlie
scoop install curlie
Haz una petición GET
:
curlie localhost:8787/api/hello
Puedes ver que el servidor devuelve la respuesta JSON que has programado:
HTTP/1.1 200 OKContent-Length: 35Content-Type: application/json
{ "ok": true, "message": "Hello Hono!"}
Una API web se compone de diferentes funciones “externas” definidas mediante un “path”.
Parámetros
Section titled “Parámetros”La mayoría de las funciones, para ser útiles, deben estar parametrizadas: deben poder recibir unos parámetros y producir un resultado diferente en función de estos parámetros.
Puedes utilizar una parte del path para identificar la función, y la otra parte del path puedes utilizarlo para definir los parámetros de entrada.
Por ejemplo, si tienes una función que muestra el perfil de cada empleado puedes utilizar el path /employee/:id
, donde /employee
es el nombre externo de la función y /:id
es el argumento de la función.
const employees = {1: {name: "David"}, 2: {name: "Dora"}}
app.get('employee/:id', (c) => { const {id} = c.req.param() return c.json({employees.id})})
Mover documentación de Rest y FastApi
Parámetros
Section titled “Parámetros”app.get('/student/:username', (c) => { const {username} = c.req.param() return c.json({"student": username})})
> curl http://127.0.0.1:8787/student/eva
Getting a path parameter, URL query value, and appending a Response header is written as follows.
app.get('/post/:id', (c) => { const page = c.req.query('page') const id = c.req.param('id') c.header('X-Message', 'Hi!') return c.text(`You want to see ${page} of ${id}`)})
We can easily handle POST, PUT, and DELETE not only GET.
app.post('/post/', (c) => c.text('Created!', 201))app.delete('/post/:id', (c) => c.text(`${c.req.param('id')} is deleted!`))
The html Helper lets you write HTML in JavaScript template literal with a tag named html
.
You have to escape these strings by yourself.
import { Hono } from 'hono'import { html} from 'hono/html'
const app = new Hono()
app.get('/student/:username', (c) => { const { username } = c.req.param() return c.html( html`<!doctype html> <h1>Hello, ${username}!</h1>` )})
Using raw()
, the content will be rendered as is.
If you want to use TSX, rename the file to src/index.tsx
and configure it (check with each runtime as it is different).
or using JSX syntax.
Below is an example using JSX.
const View = () => { return ( <html> <body> <h1>Hello Hono!</h1> </body> </html> )}
app.get('/page', (c) => { return c.html(<View />)})
MongoDB
Section titled “MongoDB”Añade una dependencia con mongodb
:
bun add mongodb
Node.js compatibility is required for database drivers, including Postgres.js, and needs to be configured for your Workers project.
Modifica el fichero wrangler.jsonc
:
// wrangler.jsonc{ "$schema": "node_modules/wrangler/config-schema.json", "name": "hono", "main": "src/index.ts", "compatibility_date": "2025-04-10", "compatibility_flags": [ "nodejs_compat" ]}
String de conexión
Section titled “String de conexión”Crea el fichero .dev.vars
para desarrollo local:
DB_CONN_STRING="mongodb+srv://<username>:<password>@cluster.2hr0xbm.mongodb.net"
Para obtener el valor de esta variable utiliza el “Adapter Helper” de Hono.
The env()
function facilitates retrieving environment variables across different runtimes:
import {Hono} from 'hono'import {env} from 'hono/adapter'
const app = new Hono()
app.get('/api/env', (c) => { const {DB_CONN_STRING} = env<{ DB_CONN_STRING: string }>(c) return c.json({DB_CONN_STRING: DB_CONN_STRING})})
Ejecuta curlie
en el endpoint
curlie localhost:8787/api/env
Puedes ver que responde con el string de conexión configurado con el fichero .dev.vars
HTTP/1.1 200 OKContent-Length: 133Content-Type: application/json
{ "DB_CONN_STRING": "mongodb+srv://<user>:<password>@cluster.ee8smuy.mongodb.net/?retryWrites=true&w=majority&appName=cluster"}
Vamos!
Section titled “Vamos!”Implementa un “endpoint” para insertar pájaros:
app.post('/api/bird/', async (c) => {
const bird = await c.req.json()
const {DB_CONN_STRING} = env<{ DB_CONN_STRING: string }>(c) const client = new MongoClient(DB_CONN_STRING)
const result = await client.db('earth').collection('birds').insertOne(bird)
return c.json({id: result.insertedId})})
Desde el terminal, envia una petición POST
al endpoint /api/bird/
curlie POST localhost:8787/api/bird/ name=swallow
Verifica que la base de datos tiene una golondrina en la colección birds
.
A continuación implementa un “endpoint” para buscar pájaros por nombre:
app.get('/api/bird/:name', async (c) => { const {name} = c.req.param()
const {DB_CONN_STRING} = env<{ DB_CONN_STRING: string }>(c)
const result = await new MongoClient(DB_CONN_STRING).db('earth').collection('birds').findOne({ name })
if (result == null){ c.notFound() } else { return c.json(result) }})
Puedes buscar un pájaro por nombre:
curlie localhost:8787/api/bird/swallow
HTTP/1.1 200 OKContent-Length: 51Content-Type: application/json
{ "_id": "68079db611c9e476456f5cbb", "name": "swallow"}
I si no lo encuentra el “endpoint” devuelve un error:
curlie localhost:8787/api/bird/turtle
404 Not Found
Cloudflare
Section titled “Cloudflare”A continuación despliega el proyecto en Cloudflare.
Primero tienes que añadir la variable DB_CONN_STRING
a tu entorno de producción:
bunx wrangler secret put DB_CONN_STRING
× Enter a secret value: mongodb+srv://<user>:<password>@cluster.ee8smuy.mongodb.net
Despliega el código en Cloudflare:
> bun run deploy...Deployed hono triggers (2.64 sec) https://hono.optersoft.workers.devCurrent Version ID: bbaafdcb-5836-4ab8-a360-bc65832aabd2
Ves a la URL que se te indica (en tu caso será diferente): https://hono.optersoft.workers.dev
Puedes ver que la aplicación se ha desplegado en Cloudflare Workers.