Deno Guide: ejemplos de trabajo con el nuevo JavaScript del lado del servidor y el tiempo de ejecución de TypeScript



¡Buen dia amigos!



Les presento la traducción del artículo "The Deno Handbook: A TypeScript Runtime Tutorial with Code Examples" de Flavio Copes.



En este artículo, aprenderemos cómo trabajar con Deno. Lo compararemos con Node.js y crearemos una API REST simple con él.



¿Qué es Deno?



Si está familiarizado con Node.js, el popular ecosistema de JavaScript del lado del servidor, Deno es prácticamente lo mismo. Casi, pero no del todo.



Comencemos con una lista de las características de Deno que más me gustan:



  • Está basado en JavaScript moderno.
  • Tiene una biblioteca estándar extensible
  • Tiene soporte estándar para TypeScript (esto significa que no tiene que compilar TypeScript manualmente, Deno lo hace automáticamente)
  • Soporta módulos ES
  • No tiene administrador de paquetes
  • Tiene un global await
  • Tiene una instalación de prueba incorporada
  • Su objetivo es la máxima compatibilidad con los navegadores. Para ello, proporciona un objeto en línea fetchy globalwindow


En este tutorial, exploraremos todas estas posibilidades.



Después de familiarizarse con Deno y sus capacidades, Node.js parecerá un poco anticuado.



Especialmente porque Node.js se basa en funciones de devolución de llamada (se escribió antes de promesas y async / await). Es poco probable que aparezcan allí alguna vez, ya que esto significa que se necesitan cambios fundamentales.



Node.js es excelente y seguirá siendo el estándar de facto en el mundo de JavaScript. Sin embargo, creo que Deno crecerá en popularidad rápidamente gracias a su compatibilidad con TypeScript y su biblioteca estándar moderna.



Deno puede permitirse un código moderno ya que no necesita compatibilidad con versiones anteriores. Por supuesto, no hay garantía de que este código se mantenga actualizado en la próxima década, pero hoy lo está.



¿Por qué Deno? ¿Porqué ahora?



Deno fue anunciado hace casi 2 años por el creador de Node.js, Ryan Dahl, en JSConf EU. Mire el video de YouTube , es muy interesante y debe verlo si está trabajando con Node.js y JavaScript.



Cada director de proyecto (creador) se ve obligado a tomar decisiones. Ryan lamenta algunas de las primeras decisiones en Node. Además, la tecnología está avanzando y JavaScript es un lenguaje completamente diferente hoy en día de lo que era en 2009 cuando Node. Piense en ES6 / 2016/2017 y así sucesivamente.



Así que decidió comenzar un nuevo proyecto, una especie de segunda ola de aplicaciones JavaScript del lado del servidor.



La razón por la que solo estoy escribiendo este artículo ahora es porque la tecnología tarda bastante en madurar. Finalmente, obtuvimos Deno 1.0 (se lanzó el 13 de mayo de 2020), la primera versión estable.



Este puede parecer un número común, pero 1.0 significa que no habrá cambios drásticos hasta Deno 2.0. A medida que aprenda nuevas tecnologías, no querrá que cambie demasiado rápido.



¿Deberías aprender Deno?



Buena pregunta.



Aprender algo nuevo como Deno requiere mucho esfuerzo. Mi consejo: si recién está comenzando con JS del lado del servidor y aún no conoce Node.js, y nunca antes ha escrito TypeScript, comience con Node.



Nadie ha sido despedido por elegir Node (parafraseando una cita famosa).



Pero si te gusta TypeScript, que no depende de una tonelada de paquetes npm, y quieres usarlo en todas partes await, Deno podría ser lo que estás buscando.



¿Reemplazará a Node.js?



No. Node.js es un gigante, una gran autoridad, una tecnología increíblemente bien respaldada que no irá a ninguna parte en la próxima década.



Compatibilidad con TypeScript de primera clase



Deno está escrito en Rust y TypeScript, ambos lenguajes muy populares en el mundo actual.



Esto significa que obtenemos muchos beneficios de TypeScript, incluso si estamos escribiendo JavaScript.



Ejecutar código TypeScript con Deno no requiere compilación previa; Deno lo hace automáticamente.



No tiene que escribir código TypeScript, pero el hecho de que el núcleo de Deno esté escrito en TypeScript marca una gran diferencia.



Primero, un gran porcentaje de desarrolladores de JavaScript aman TypeScript.



En segundo lugar, las herramientas que utiliza pueden obtener mucha información sobre software escrito en TypeScript como Deno.



Esto significa que cuando escribimos código en VS Code, por ejemplo (que tiene una estrecha integración con TypeScript desde su inicio), obtenemos beneficios como la verificación de tipos al escribir código o capacidades avanzadas de IntelliSense. En otras palabras, la ayuda del editor de código se vuelve mucho más eficiente.



Diferencias con Node.js



Dado que Deno es esencialmente un reemplazo de Node.js, tiene sentido comparar los dos.



General:



  • Ambos se basan en el motor V8
  • Ambos son excelentes para el desarrollo de JavaScript del lado del servidor


Diferencias:



  • El nodo está escrito en C ++ y JavaScript. Deno está escrito en Rust y TypeScript.
  • Node tiene un administrador de paquetes oficial npm. Deno no tiene tal administrador, en cambio le permite importar cualquier módulo usando una URL.
  • Node usa la sintaxis CommonJS para importar paquetes. Deno utiliza la forma oficial: módulos ES.
  • Deno ECMAScript , Node.js .
  • Deno () . . Node.js , .
  • Deno , .. , , Go, . .




No tener un administrador de paquetes y usar una URL para obtener e importar paquetes tiene sus ventajas y desventajas. Una de las principales ventajas es la gran flexibilidad en la capacidad de crear paquetes sin tener que publicarlos en un repositorio como npm.



Creo que tarde o temprano aparecerá alguna alternativa al administrador de paquetes en Deno.



El sitio web oficial de Deno aloja paquetes de terceros: https://deno.land/x/



Instalación de Deno



¡Basta de hablar! Instalemos Deno.



La forma más sencilla de hacer esto es usando Homebrew:



    brew install deno 






Aquí se enumeran otros métodos de instalación .



Después de la instalación, el comando está disponible deno. Aquí está la ayuda que puede obtener escribiendo deno --help:



flavio@mbp~> deno --help
deno 0.42.0
A secure JavaScript and TypeScript runtime

Docs: https://deno.land/std/manual.md
Modules: https://deno.land/std/ https://deno.land/x/
Bugs: https://github.com/denoland/deno/issues

To start the REPL, supply no arguments:
  deno

To execute a script:
  deno run https://deno.land/std/examples/welcome.ts
  deno https://deno.land/std/examples/welcome.ts

To evaluate code in the shell:
  deno eval "console.log(30933 + 404)"

Run 'deno help run' for 'run'-specific flags.

USAGE:
    deno [OPTIONS] [SUBCOMMAND]

OPTIONS:
    -h, --help
            Prints help information

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -V, --version
            Prints version information


SUBCOMMANDS:
    bundle         Bundle module and dependencies into single file
    cache          Cache the dependencies
    completions    Generate shell completions
    doc            Show documentation for a module
    eval           Eval script
    fmt            Format source files
    help           Prints this message or the help of the given subcommand(s)
    info           Show info about cache or info related to source file
    install        Install script as an executable
    repl           Read Eval Print Loop
    run            Run a program given a filename or url to the module
    test           Run tests
    types          Print runtime TypeScript declarations
    upgrade        Upgrade deno executable to newest version

ENVIRONMENT VARIABLES:
    DENO_DIR             Set deno's base directory (defaults to $HOME/.deno)
    DENO_INSTALL_ROOT    Set deno install's output directory
                         (defaults to $HOME/.deno/bin)
    NO_COLOR             Set to disable color
    HTTP_PROXY           Proxy address for HTTP requests
                         (module downloads, fetch)
    HTTPS_PROXY          Same but for HTTPS


Equipos Deno



¿Notaste la sección SUBCOMMANDS? Esta es una lista de todos los comandos que podemos ejecutar. ¿Qué equipos tenemos?



  • bundle - recopila las dependencias del módulo y del proyecto en un archivo
  • cache - caché de dependencias
  • completions - genera recargas de cáscara
  • doc - muestra la documentación del módulo
  • eval - utilizado para calcular un bloque de código, por ejemplo deno eval "console.log(1 + 2)"
  • fmt- formateador de código incorporado (como goFmten Go)
  • help - muestra una lista de comandos auxiliares
  • info - muestra información sobre la caché o el archivo
  • install - establece el script como ejecutable
  • repl - ciclo de lectura-cálculo-salida (predeterminado)
  • run - ejecuta el programa con el nombre dado o la URL del módulo
  • test - ejecuta pruebas
  • types - muestra una lista de características de TypeScript
  • upgrade - actualiza Deno a la última versión


Puede ejecutar deno <subcommand> helppara obtener información sobre un comando específico, por ejemplo deno run --help.



Podemos usar un comando denopara iniciar un ciclo de lectura-evaluación-salida:







esto es lo mismo que comenzar deno repl.



Normalmente se denoutiliza para iniciar una aplicación Deno contenida en un archivo TypeScript.



Puede ejecutar archivos TypeScript (.ts) y archivos JavaScript (.js).



Si es nuevo en TypeScript, no se preocupe: Deno está escrito en TypeScript, pero puede escribir sus aplicaciones cliente en JavaScript.



Primera aplicación en Deno



Creemos nuestra primera aplicación.



Para ello, ni siquiera tenemos que escribir código, lo ejecutaremos en el terminal usando la URL.



Deno descarga el programa, lo compila y lo ejecuta:







Por supuesto, no recomendaría ejecutar código aleatorio de Internet. En este caso, lo estamos lanzando desde el sitio oficial de Deno, además, Deno tiene una caja de arena que evita que los programas hagan lo que no les permitimos explícitamente hacer.



Este programa es muy simple y es una llamada console.log():



console.log('Welcome to Deno ') //     ,    


Si abre https://deno.land/std/examples/welcome.ts en un navegador, verá lo siguiente:







Extraño, ¿no? Probablemente esperaba ver un archivo TypeScript, pero en su lugar obtuvo una página web. El punto es que el servidor del sitio web de Deno sabe que está utilizando un navegador y le proporciona una página más fácil de usar.



Cargue la misma URL usando wget, por ejemplo, y obtenga en su text/plainlugar text/html:







Cuando reinicia el programa, gracias al almacenamiento en caché, no es necesario reiniciar:







Usando una bandera, --reloadpuede realizar un reinicio forzado:







deno runtiene muchas funciones diferentes que no se muestran deno --help. Para verlos, debe ejecutar deno run --help:



flavio@mbp~> deno run --help
deno-run
Run a program given a filename or url to the module.

By default all programs are run in sandbox without access to disk, network or
ability to spawn subprocesses.
    deno run https://deno.land/std/examples/welcome.ts

Grant all permissions:
    deno run -A https://deno.land/std/http/file_server.ts

Grant permission to read from disk and listen to network:
    deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts

Grant permission to read whitelisted files from disk:
    deno run --allow-read=/etc https://deno.land/std/http/file_server.ts

USAGE:
    deno run [OPTIONS] <SCRIPT_ARG>...

OPTIONS:
    -A, --allow-all
            Allow all permissions

        --allow-env
            Allow environment access

        --allow-hrtime
            Allow high resolution time measurement

        --allow-net=<allow-net>
            Allow network access

        --allow-plugin
            Allow loading plugins

        --allow-read=<allow-read>
            Allow file system read access

        --allow-run
            Allow running subprocesses

        --allow-write=<allow-write>
            Allow file system write access

        --cached-only
            Require that remote dependencies are already cached

        --cert <FILE>
            Load certificate authority from PEM encoded file

    -c, --config <FILE>
            Load tsconfig.json configuration file

    -h, --help
            Prints help information

        --importmap <FILE>
            UNSTABLE:
            Load import map file
            Docs: https://deno.land/std/manual.md#import-maps
            Specification: https://wicg.github.io/import-maps/
            Examples: https://github.com/WICG/import-maps#the-import-map
        --inspect=<HOST:PORT>
            activate inspector on host:port (default: 127.0.0.1:9229)

        --inspect-brk=<HOST:PORT>
            activate inspector on host:port and break at start of user script

        --lock <FILE>
            Check the specified lock file

        --lock-write
            Write lock file. Use with --lock.

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

        --no-remote
            Do not resolve remote modules

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -r, --reload=<CACHE_BLACKLIST>
            Reload source code cache (recompile TypeScript)
            --reload
                Reload everything
            --reload=https://deno.land/std
                Reload only standard modules
            --reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts
                Reloads specific modules
        --seed <NUMBER>
            Seed Math.random()

        --unstable
            Enable unstable APIs

        --v8-flags=<v8-flags>
            Set V8 command line options. For help: --v8-flags=--help


ARGS:
    <SCRIPT_ARG>...
            script args


Ejemplos de código



Hay otros ejemplos en el sitio web de Deno que se pueden encontrar aquí .



En el momento de escribir este artículo, se puede encontrar lo siguiente en el repositorio especificado:



  • cat.ts - muestra el contenido de los archivos pasados ​​como argumentos
  • catj.ts- hace lo mismo, cat.tspero primero realiza algunas manipulaciones con el contenido de los archivos
  • chat/ - implementación de chat
  • colors.ts - un ejemplo de estilo de texto usando módulos
  • curl.ts- una implementación simple curlque genera el contenido de la URL pasada como argumento
  • echo_server.ts - servidor de eco TCP
  • gist.ts - programa para colocar archivos en gist.github.com
  • test.ts - programa de prueba
  • welcome.ts - el programa que lanzamos
  • xeval.ts- le permite ejecutar TypeScript obtenido de cualquier fuente de datos estándar. deno xevalha sido eliminado de la lista de equipos oficiales


Primera aplicación real en Deno



Escribamos un código.



La primera aplicación con la que lanzamos deno run https://deno.land/std/examples/welcome.tsya estaba escrita, por lo que no ha aprendido nada nuevo sobre Deno.



Comencemos con un ejemplo estándar publicado en el sitio web de Deno:



import { serve } from 'https://deno.land/std/http/server.ts'
const s = serve({ port: 8000 })
console.log('http://localhost:8000/')
for await (const req of s) {
    req.respond({ body: 'Hello World\n' })
}


Aquí estamos importando una función servede un módulo http/server. ¿Ver? No tuvimos que instalarlo y no está almacenado en nuestra computadora como los módulos de nodo. Esta es una de las razones de la rápida instalación de Deno.



Con la ayuda https://deno.land/std/http/server.tsimportamos la última versión del módulo. Se puede importar una versión específica usando @VERSION:



import { serve } from 'https://deno.land/std@v0.42.0/http/server.ts'


Esta es la función serve:



/**
 * Create a HTTP server
 *
 *     import { serve } from "https://deno.land/std/http/server.ts";
 *     const body = "Hello World\n";
 *     const s = serve({ port: 8000 });
 *     for await (const req of s) {
 *       req.respond({ body });
 *     }
 */
 export function serve(addr: string | HTTPOptions): Server {
  if (typeof addr === 'string') {
    const [hostname, port] = addr.split(':')
    addr = { hostname, port: Number(port) }
  }

  const listener = listen(addr)
  return new Server(listener)
}


A continuación, llamamos a la función serve()y le pasamos un objeto con una propiedad port.



Luego ejecutamos un ciclo para responder a cada solicitud del servidor:



for await (const req of s) {
  req.respond({ body: 'Hello World\n' })
}


Tenga en cuenta que estamos usando la palabra clave awaitsin envolver el código en una asyncfunción.



Ejecutemos el programa localmente. Estoy usando VS Code, pero puedes usar cualquier editor.



Recomiendo instalar una extensión de justjavac (hay otra con un nombre similar, pero está obsoleta y puede desaparecer en el futuro): la







extensión proporciona varias utilidades para ayudarlo a escribir aplicaciones Deno.



Creemos un archivo app.tsy peguemos nuestro código en él:







Ejecutarlo con deno run app.ts:







Deno cargará todas las dependencias que necesita el programa, pero primero la que importamos en el archivo.



El archivo https://deno.land/std/http/server.ts tiene varias dependencias propias:



import { encode } from '../encoding/utf8.ts'
import { BufReader, BufWriter } from '../io/bufio.ts'
import { assert } from '../testing/asserts.ts'
import { deferred, Deferred, MuxAsyncIterator } from '../async/mod.ts'
import {
    bodyReader,
    chunkedBodyReader,
    emptyReader,
    writeResponse,
    readRequest,
} from './_io.ts'
import Listener = Deno.Listener
import Conn = Deno.Conn
import Reader = Deno.Reader


Estas dependencias se importan automáticamente.



Al final, tenemos un problema:







¿Qué está pasando? Tenemos un error de permiso denegado.



Hablemos de la caja de arena.



Salvadera



Como mencioné anteriormente, Deno tiene una caja de arena que evita que los programas hagan cosas para las que no han sido autorizados.



¿Qué significa esto?



Como dice Ryan en su charla, a veces desea ejecutar un programa JavaScript fuera del navegador y no desea que el programa tenga acceso a todo en su sistema. O cuando se trata del mundo exterior usando la red.



Nada impide que la aplicación Node.js obtenga su clave SSH u otra información de su sistema y la envíe al servidor. Es por eso que generalmente solo instalamos paquetes de Node de fuentes confiables. Pero, ¿cómo sabemos si uno de los proyectos que estamos usando ha sido pirateado?



Deno imita el sistema de permisos utilizado por el navegador. El código JavaScript que se ejecuta en un navegador no puede hacer nada con su sistema a menos que usted lo permita explícitamente.



Volviendo a Deno, si un programa necesita acceso a la red, tenemos que darle permiso para hacerlo.



Esto se hace usando la bandera --allow-net:



deno run --allow-net app.ts






El servidor ahora se está ejecutando en el puerto 8000:







Otros indicadores:



  • --allow-env - permite el acceso a variables de entorno
  • --allow-hrtime - permite la medición de alta resolución
  • --allow-net=<allow-net> - permite el acceso a la red
  • --allow-plugin - permite cargar complementos
  • --allow-read=<allow-read> - permite leer archivos
  • --allow-run - permite iniciar subprocesos
  • --allow-write=<allow-write> - permite escribir archivos
  • --allow-all- otorga todos los permisos (similar -A)


Permisos para net, ready writepueden ser parcial. Por ejemplo, podemos permitir que los archivos de sólo lectura que se encuentran en un determinado directorio: --allow-read=/dev.



Formato de código



Una de las cosas que me encanta de Go es el comando gofmt. Todo el código de Go tiene el mismo aspecto. Todo el mundo lo está usando gofmt.



Los desarrolladores de JavaScript suelen usar Prettier y, deno fmtde hecho, también lo usan debajo del corte.



Digamos que tiene un archivo tan mal formateado:







comienza deno fmt app.tsy el formateo automático se lleva a cabo sin punto y coma:







Biblioteca estándar



La biblioteca estándar de Deno es bastante extensa a pesar de la antigüedad del proyecto.



Incluye lo siguiente:



  • archieve - utilidades para archivar
  • async - utilidades para trabajar con código asincrónico
  • bytes - funciones auxiliares para dividir bytes
  • datetime - análisis de fechas / horas
  • encoding - codificación / decodificación en diferentes formatos
  • flags - análisis de indicadores de línea de comando
  • fmt - formación y exhibición
  • fs - interfaz de aplicación para trabajar con el sistema de archivos
  • hash - biblioteca de cifrado
  • http - servidor HTTP
  • io - biblioteca de operaciones de entrada / salida
  • log - utilidades para la tala
  • mime - soporte de datos mixtos
  • node - capa de compatibilidad con versiones anteriores de Node
  • path - trabajar con caminos
  • ws - enchufes web


Un ejemplo mas



Echemos un vistazo a otro ejemplo oficial cat.ts:



const filenames = Deno.args
for (const filename of filenames) {
    const file = await Deno.open(filename)
    await Deno.copy(file, Deno.stdout)
    file.close()
}


Asignamos filenamescontenido a una variable Deno.args, que es una variable que contiene los argumentos pasados ​​usando la línea de comando.



Los iteramos y para cada uno, primero los usamos Deno.open()para abrir el archivo y luego Deno.copy()copiamos el contenido en Deno.stdout. Finalmente, cerramos el archivo.



Si tu corres:



deno run https://deno.land/std/examples/cat.ts


El programa se cargará y compilará, pero no pasa nada porque no pasamos ningún argumento.



Ahora intentemos esto:



deno run https://deno.land/std/examples/cat.ts app.ts


Obtenemos error de permiso:







Deno no tiene acceso al sistema por defecto. Démosle este permiso con --allow-read:



deno run --allow-read=./ https://deno.land/std/examples/cat.ts app.ts






¿Existe Express / Hapi / Koa / * para Deno?



Oh, por supuesto. Eche un vistazo a los siguientes proyectos:





Ejemplo: usar Oak para crear una API REST



Voy a crear una API REST usando Oak. Oak es interesante porque está inspirado en Koa, un middleware popular para NOde.js, y tiene una sintaxis similar.



Nuestra API será muy sencilla.



Nuestro servidor almacenará en memoria una lista de perros, sus nombres y edades.



Queremos obtener la siguiente funcionalidad:



  • agregar nuevos perros a la lista
  • obtener una lista de todos los perros
  • obtener información sobre un perro específico
  • eliminar un perro de la lista
  • actualizar la edad del perro


Escribiremos el código en Typecript, pero nada le impide hacerlo en JavaScript, simplemente no especifique los tipos de datos.



Creamos un archivo app.ts.



Comencemos por importar objetos desde Applicationy Routerhacia Oak:



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'


Obtenemos las variables de entorno PORT y HOST:



const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'


De forma predeterminada, nuestra aplicación se ejecutará en localhost: 4000.



Cree una aplicación Oak y ejecútela:



const router = new Router()

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


La aplicación debería funcionar ahora.



Verificamos:



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


Deno descarga las dependencias:







Y comienza a escuchar en el puerto 4000.



Al reiniciar, el paso de instalación se omitirá gracias al almacenamiento en caché:







Defina una interfaz para el perro, luego defina una matriz que dogcontenga los objetos Dog:



interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]


Comencemos a implementar la API.



Todo está en su lugar. Agreguemos algunas funciones al enrutador que se llamará al acceder al punto final especificado:



const router = new Router()

router
    .get('/dogs', getDogs)
    .get('/dogs/:name', getDog)
    .post('/dogs', addDog)
    .put('/dogs/:name', updateDog)
    .delete('/dogs/:name', removeDog)


Hemos definido lo siguiente:



  • GET /dogs
  • GET /dogs/:name
  • POST /dogs
  • PUT /dogs/:name
  • DELETE /dogs/:name




Implementemos estas rutas una por una.



Comencemos con GET /dogs, que devuelve una lista de todos los perros:



export const getDogs = ({ response }: { response: any }) => {
    response.body = dogs
}






A continuación, le indicamos cómo obtener un perro específico por nombre:



export const getDog = ({
  params,
  response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const dog = dogs.filter(dog => dog.name === params.name)
    if (dog.length) {
        response.status = 200
        response.body = dog[0]
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






A continuación, se explica cómo agregar un perro nuevo a la lista:



export const addDog = async ({
    request,
    response,
}: {
    request: any
    response: any
}) => {
    const body = await request.body()
    const dog: Dog = await body.value
    dogs.push(dog)

    response.body = { msg: 'OK' }
    response.status = 200
}






A continuación, le indicamos cómo actualizar la edad de su perro:



export const updateDog = async ({
    params,
    request,
    response,
}: {
    params: {
        name: string
    },
    request: any
    response: any
}) => {
    const temp = dogs.filter((existingDog) => existingDog.name === params.name)
    const body = await request.body()
    const { age }: { age: number } = await body.value

    if (temp.length) {
        temp[0].age = age
        response.status = 200
        response.body = { msg: 'OK' }
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






Y aquí se explica cómo eliminar un perro de la lista:



export const removeDog = ({
    params,
    response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const lengthBefore = dogs.length
    dogs = dogs.filter((dog) => dog.name !== params.name)

    if (dogs.length === lengthBefore) {
        response.status = 400
        response.body = { msg: `Cannot find dog ${params.name}` }
        return
    }

    response.body = { msg: 'OK' }
    response.status = 200
}






Código de aplicación completo:



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'

const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'

interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]

export const getDogs = ({ response }: { response: any }) => {
  response.body = dogs
}

export const getDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const dog = dogs.filter(dog => dog.name === params.name)
  if (dog.length) {
    response.status = 200
    response.body = dog[0]
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const addDog = async ({
  request,
  response,
}: {
  request: any
  response: any
}) => {
  const body = await request.body()
  const { name, age }: { name: string; age: number } = await body.value
  dogs.push({
    name: name,
    age: age,
  })

  response.body = { msg: 'OK' }
  response.status = 200
}

export const updateDog = async ({
  params,
  request,
  response,
}: {
  params: {
    name: string
  },
  request: any
  response: any
}) => {
  const temp = dogs.filter((existingDog) => existingDog.name === params.name)
  const body = await request.body()
  const { age }: { age: number } = await body.value

  if (temp.length) {
    temp[0].age = age
    response.status = 200
    response.body = { msg: 'OK' }
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const removeDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const lengthBefore = dogs.length
  dogs = dogs.filter(dog => dog.name !== params.name)

  if (dogs.length === lengthBefore) {
    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
    return
  }

  response.body = { msg: 'OK' }
  response.status = 200
}

const router = new Router()
router
  .get('/dogs', getDogs)
  .get('/dogs/:name', getDog)
  .post('/dogs', addDog)
  .put('/dogs/:name', updateDog)
  .delete('/dogs/:name', removeDog)

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


Gracias por su atención.