Guia Deno: exemplos de trabalho com o novo JavaScript do lado do servidor e o tempo de execução do TypeScript



Bom dia amigos!



Apresento a sua atenção a tradução do artigo "The Deno Handbook: A TypeScript Runtime Tutorial with Code Examples" de Flavio Copes.



Neste artigo, aprenderemos como trabalhar com Deno. Vamos compará-lo ao Node.js e construir uma API REST simples com ele.



O que é Deno?



Se você está familiarizado com Node.js, o popular ecossistema JavaScript do lado do servidor, Deno é praticamente a mesma coisa. Quase, mas não exatamente.



Vamos começar com uma lista dos recursos do Deno que mais gosto:



  • É baseado em JavaScript moderno
  • Possui uma biblioteca padrão extensível
  • Ele tem suporte para TypeScript padrão (isso significa que você não precisa compilar manualmente o TypeScript, o Deno faz isso automaticamente)
  • Suporta módulos ES
  • Não tem gerenciador de pacotes
  • Tem um global await
  • Tem uma instalação de teste embutida
  • Seu objetivo é a compatibilidade máxima do navegador. Para isso, ele fornece um fetchobjeto inline e um globalwindow


Neste tutorial, exploraremos todas essas possibilidades.



Depois de se familiarizar com o Deno e seus recursos, o Node.js parecerá um pouco desatualizado.



Especialmente porque o Node.js é baseado em funções de retorno de chamada (ele foi escrito antes de promises e async / await). É improvável que eles apareçam lá, pois isso significa que mudanças fundamentais são necessárias.



O Node.js é ótimo e continuará sendo o padrão de fato no mundo do JavaScript. No entanto, acredito que a popularidade do Deno crescerá rapidamente graças ao seu suporte TypeScript e à biblioteca padrão moderna.



O Deno pode pagar um código moderno, pois não precisa de compatibilidade com versões anteriores. Claro, não há garantia de que esse código permanecerá atualizado na próxima década, mas hoje está.



Por que Deno? Porque agora?



Deno foi anunciado há quase 2 anos pelo criador do Node.js, Ryan Dahl, na JSConf EU. Assista ao vídeo do YouTube , é muito interessante e imperdível se você está trabalhando com Node.js e JavaScript.



Cada gerente de projeto (criador) é forçado a tomar decisões. Ryan lamenta algumas das primeiras decisões em Node. Além disso, a tecnologia avança e o JavaScript é uma linguagem completamente diferente hoje do que era em 2009 quando o Node. Pense no ES6 / 2016/2017 e assim por diante.



Então ele decidiu iniciar um novo projeto, uma espécie de segunda onda de aplicativos JavaScript do lado do servidor.



Só estou escrevendo este artigo agora porque leva muito tempo para a tecnologia amadurecer. Por fim, obtivemos o Deno 1.0 (lançado em 13 de maio de 2020), a primeira versão estável.



Este pode parecer um número comum, mas 1.0 significa que não haverá nenhuma mudança drástica até o Deno 2.0. Ao aprender uma nova tecnologia, você não quer que ela mude muito rapidamente.



Você deve aprender Deno?



Boa pergunta.



Aprender algo novo como Deno exige muito esforço. Meu conselho: se você está apenas começando com JS do lado do servidor e não conhece o Node.js ainda, e nunca escreveu TypeScript antes, comece com o Node.



Ninguém foi demitido por escolher a Node ainda (parafraseando uma frase famosa).



Mas se você gosta do TypeScript, que não depende de muitos pacotes npm, e quer usá-lo em qualquer lugar await, o Deno pode ser o que você está procurando.



Ele substituirá o Node.js?



Não. O Node.js é um gigante, uma grande autoridade, uma tecnologia incrivelmente bem suportada que não chegará a lugar nenhum na próxima década.



Suporte TypeScript de primeira classe



Deno é escrito em Rust e TypeScript, duas linguagens muito populares no mundo de hoje.



Isso significa que obtemos muitos benefícios do TypeScript, mesmo que estejamos escrevendo JavaScript.



A execução do código TypeScript com Deno não requer compilação - Deno faz isso automaticamente.



Você não precisa escrever código TypeScript, mas o fato de o núcleo do Deno ser escrito em TypeScript faz uma grande diferença.



Primeiro, uma grande porcentagem de desenvolvedores de JavaScript ama o TypeScript.



Em segundo lugar, as ferramentas que você usa podem obter muitas informações sobre softwares escritos em TypeScript, como o Deno.



Isso significa que, quando escrevemos código em VS Code, por exemplo (que foi totalmente integrado ao TypeScript desde seu início), obtemos benefícios como verificação de tipo ao escrever código ou recursos avançados de IntelliSense. Em outras palavras, a ajuda do editor de código se torna muito mais eficiente.



Diferenças do Node.js



Como o Deno é essencialmente um substituto do Node.js, faz sentido comparar os dois.



Geral:



  • Ambos são baseados no motor V8
  • Ambos são ótimos para o desenvolvimento de JavaScript do lado do servidor


Diferenças:



  • O Node é escrito em C ++ e JavaScript. Deno é escrito em Rust e TypeScript.
  • O Node possui um gerenciador de pacotes oficial npm. O Deno não tem esse gerenciador; em vez disso, ele permite importar qualquer módulo usando uma URL.
  • O Node usa a sintaxe CommonJS para importar pacotes. Deno usa a forma oficial - módulos ES.
  • Deno ECMAScript , Node.js .
  • Deno () . . Node.js , .
  • Deno , .. , , Go, . .




Não ter um gerenciador de pacotes e usar uma URL para obter e importar pacotes tem suas vantagens e desvantagens. Uma das principais vantagens é a grande flexibilidade na capacidade de criar pacotes sem ter que publicá-los em um repositório como o npm.



Acho que alguma alternativa ao gerenciador de pacotes no Deno aparecerá mais cedo ou mais tarde.



O site oficial da Deno está hospedando pacotes de terceiros: https://deno.land/x/



Instalando Deno



Chega de conversa! Vamos instalar o Deno.



A maneira mais fácil de fazer isso é usando o Homebrew:



    brew install deno 






Outros métodos de instalação estão listados aqui .



Após a instalação, o comando fica disponível deno. Aqui está a ajuda que você pode obter digitando 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


Deno Times



Você notou a seção SUBCOMMANDS? Esta é uma lista de todos os comandos que podemos executar. Que times nós temos?



  • bundle - coleta o módulo e as dependências do projeto em um arquivo
  • cache - armazena dependências
  • completions - gera recargas de shell
  • doc - mostra a documentação do módulo
  • eval - usado para calcular um bloco de código, por exemplo deno eval "console.log(1 + 2)"
  • fmt- formatador de código integrado (como goFmtem Go)
  • help - exibe uma lista de comandos auxiliares
  • info - mostra informações sobre o cache ou arquivo
  • install - define o script como executável
  • repl - ciclo de leitura-cálculo-saída (padrão)
  • run - executa o programa com o nome ou URL fornecido para o módulo
  • test - executa testes
  • types - exibe uma lista de recursos do TypeScript
  • upgrade - atualiza Deno para a versão mais recente


Você pode executar deno <subcommand> helppara obter informações sobre um comando específico, por exemplo deno run --help.



Podemos usar um comando denopara iniciar um loop de leitura-avaliação-saída:







Isso é o mesmo que iniciar deno repl.



Normalmente denousado para iniciar um aplicativo Deno contido em um arquivo TypeScript.



Você pode executar arquivos TypeScript (.ts) e arquivos JavaScript (.js).



Se você não estiver familiarizado com o TypeScript, não se preocupe: Deno é escrito em TypeScript, mas você pode escrever seus aplicativos cliente em JavaScript.



Primeiro aplicativo no Deno



Vamos criar nosso primeiro aplicativo.



Para fazer isso, não precisamos nem escrever código, vamos executá-lo no terminal usando a URL.



Deno baixa o programa, compila-o e executa-o:







claro, não recomendo executar código aleatório da Internet. Neste caso, estamos lançando-o do site oficial do Deno, além disso, o Deno tem uma sandbox que impede os programas de fazerem o que não permitimos explicitamente.



Este programa é muito simples e é uma chamada console.log():



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


Se você abrir https://deno.land/std/examples/welcome.ts em um navegador, verá o seguinte:







Estranho, não é? Você provavelmente esperava ver um arquivo TypeScript, mas, em vez disso, obteve uma página da web. A questão é que o servidor do site Deno sabe que você está usando um navegador e fornece uma página mais amigável.



Carregue a mesma URL usando wget, por exemplo, e obtenha text/plainem seu lugar text/html:







Quando você reinicia o programa, graças ao cache, nenhuma reinicialização é necessária: Uma reinicialização forçada pode ser executada







usando o sinalizador --reload:







deno runtem muitas funções diferentes que não são exibidas por deno --help. Para vê-los, você deve executar 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


Exemplos de código



Existem outros exemplos no site do Deno que podem ser encontrados aqui .



No momento da redação deste artigo, o seguinte poderia ser encontrado no repositório especificado:



  • cat.ts - exibe o conteúdo dos arquivos passados ​​como argumentos
  • catj.ts- faz a mesma coisa, cat.tsmas primeiro executa algumas manipulações com o conteúdo dos arquivos
  • chat/ - implementação de chat
  • colors.ts - um exemplo de estilização de texto usando módulos
  • curl.ts- uma implementação simples curlque produz o conteúdo do URL passado como um argumento
  • echo_server.ts - servidor de eco TCP
  • gist.ts - programa para colocar arquivos em gist.github.com
  • test.ts - programa de teste
  • welcome.ts - o programa que lançamos
  • xeval.ts- permite que você execute o TypeScript obtido de qualquer fonte de dados padrão. deno xevalfoi removido da lista de times oficiais


Primeiro aplicativo real no Deno



Vamos escrever algum código.



O primeiro aplicativo com o qual lançamos deno run https://deno.land/std/examples/welcome.tsjá foi escrito, então você não aprendeu nada novo sobre o Deno.



Vamos começar com um exemplo padrão postado no site 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' })
}


Aqui estamos importando uma função servede um módulo http/server. Vejo? Não foi necessário instalá-lo e ele não está armazenado em nosso computador como os módulos Node. Este é um dos motivos da rápida instalação do Deno.



Com a ajuda https://deno.land/std/http/server.ts, importamos a versão mais recente do módulo. Uma versão específica pode ser importada usando @VERSION:



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


Esta é a função 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)
}


Em seguida, chamamos a função serve()e passamos a ela um objeto com uma propriedade port.



Em seguida, executamos um loop para responder a cada solicitação do servidor:



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


Observe que estamos usando a palavra-chave awaitsem envolver o código em uma asyncfunção.



Vamos executar o programa localmente. Estou usando o VS Code, mas você pode usar qualquer editor.



Eu recomendo instalar uma extensão de justjavac (há outra com um nome semelhante, mas está obsoleta e pode desaparecer no futuro): A







extensão fornece vários utilitários para ajudá-lo a escrever aplicativos Deno.



Vamos criar um arquivo app.tse colar nosso código nele:







Execute-o com deno run app.ts:







Deno irá carregar todas as dependências que o programa precisa, mas primeiro a que importamos no arquivo.



O arquivo https://deno.land/std/http/server.ts tem várias dependências próprias:



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


Essas dependências são importadas automaticamente.



No final, temos um problema: o







que está acontecendo? Recebemos um erro de permissão negada.



Vamos falar sobre a sandbox.



Caixa de areia



Como mencionei antes, o Deno tem uma sandbox que impede os programas de fazer coisas para as quais não receberam permissão.



O que isto significa?



Como Ryan disse em sua palestra, às vezes você deseja executar um programa JavaScript fora do navegador e não deseja que o programa tenha acesso a tudo em seu sistema. Ou quando se trata do mundo externo usando a rede.



Nada impede que o aplicativo Node.js obtenha sua chave SSH ou outras informações de seu sistema e as envie para o servidor. É por isso que normalmente só instalamos pacotes Node de fontes confiáveis. Mas como sabemos se um dos projetos que estamos usando foi hackeado?



Deno imita o sistema de permissão usado pelo navegador. O código JavaScript em execução em um navegador não pode fazer nada com o seu sistema, a menos que você permita explicitamente.



Voltando ao Deno, se um programa precisa de acesso à rede, temos que dar a ele permissão para fazê-lo.



Isso é feito usando o sinalizador --allow-net:



deno run --allow-net app.ts






O servidor agora está sendo executado na porta 8000:







Outros sinalizadores:



  • --allow-env - permite acesso a variáveis ​​de ambiente
  • --allow-hrtime - permite medição de alta resolução
  • --allow-net=<allow-net> - permite acesso à rede
  • --allow-plugin - permite carregar plugins
  • --allow-read=<allow-read> - permite a leitura de arquivos
  • --allow-run - permite iniciar subprocessos
  • --allow-write=<allow-write> - permite gravar arquivos
  • --allow-all- concede todas as permissões (semelhante -A)


Permissões para net, reade writepode ser parcial. Por exemplo, podemos permitir que arquivos somente leitura que estão em um determinado diretório: --allow-read=/dev.



Formatação de código



Uma das coisas que adoro no Go é o comando gofmt. Todo o código Go parece o mesmo. Todo mundo está usando gofmt.



Os desenvolvedores de JavaScript geralmente usam o Prettier e, deno fmtna verdade, também o usam em segundo plano.



Digamos que você tenha um arquivo mal formatado:







você inicia deno fmt app.tse a formatação automática ocorre sem ponto-e-vírgula:







Biblioteca padrão



A biblioteca padrão de Deno é bastante extensa, apesar da idade do projeto.



Inclui o seguinte:



  • archieve - utilitários para arquivamento
  • async - utilitários para trabalhar com código assíncrono
  • bytes - funções auxiliares para divisão de bytes
  • datetime - análise de datas / horas
  • encoding - codificação / decodificação em diferentes formatos
  • flags - analisando sinalizadores de linha de comando
  • fmt - formação e exibição
  • fs - interface do aplicativo para trabalhar com o sistema de arquivos
  • hash - biblioteca de criptografia
  • http - servidor HTTP
  • io - biblioteca de operações de entrada / saída
  • log - utilitários para registro
  • mime - suporte de dados mistos
  • node - camada de compatibilidade retroativa com Node
  • path - trabalhar com caminhos
  • ws - soquetes web


Mais um exemplo



Vamos dar uma olhada em outro exemplo 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()
}


Atribuímos filenamesconteúdo a uma variável Deno.args, que é uma variável que contém os argumentos passados ​​usando a linha de comando.



Nós iteramos sobre eles e, para cada um, primeiro os usamos Deno.open()para abrir o arquivo e, em seguida, Deno.copy()copiamos o conteúdo para Deno.stdout. Finalmente, fechamos o arquivo.



Se você executar:



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


O programa irá carregar e compilar, mas nada acontece porque não passamos nenhum argumento.



Agora vamos tentar isso:



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


Recebemos erro de permissão:







Deno não tem acesso ao sistema por padrão. Vamos conceder a ele essa permissão com --allow-read:



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






Expresso / Hapi / Koa / * existe para Deno?



Ah com certeza. Dê uma olhada nos seguintes projetos:





Exemplo: usando Oak para criar uma API REST



Vou criar uma API REST usando Oak. Oak é interessante porque é inspirado em Koa, o middleware popular para NOde.js, e tem uma sintaxe semelhante.



Nossa API será muito simples.



Nosso servidor armazenará na memória uma lista de cães, seus nomes e idades.



Queremos obter a seguinte funcionalidade:



  • adicionar novos cachorros à lista
  • obtenha uma lista de todos os cães
  • obter informações sobre um cachorro específico
  • remova um cachorro da lista
  • atualizar a idade do cachorro


Estaremos escrevendo o código em Typescript, mas nada impede que você faça isso em JavaScript - apenas não especifique os tipos de dados.



Criamos um arquivo app.ts.



Vamos começar importando objetos de Applicatione Routerpara Oak:



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


Obtemos as variáveis ​​de ambiente PORT e HOST:



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


Por padrão, nosso aplicativo será executado em localhost: 4000.



Crie um aplicativo Oak e inicie-o:



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}`)


O aplicativo agora deve funcionar.



Nós verificamos:



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


O Deno baixa as dependências:







E começa a escutar na porta 4000.



Na reinicialização, a etapa de instalação será ignorada graças ao cache:







Defina uma interface para o cão e, em seguida, defina um array dogcontendo os objetos Dog:



interface Dog {
  name: string
  age: number
}

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


Vamos começar a implementar a API.



Tudo está no lugar. Vamos adicionar algumas funções ao roteador que serão chamadas ao acessar o endpoint especificado:



const router = new Router()

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


Nós definimos o seguinte:



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




Vamos implementar essas rotas uma por uma.



Vamos começar com GET /dogs, que retorna uma lista de todos os cães:



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






Veja como obter um cachorro específico pelo nome:



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}` }
}






Veja como adicionar um novo cachorro à 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
}






Veja como atualizar a idade do seu cão:



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}` }
}






E aqui está como remover um cachorro da 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 completo do aplicativo:



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}`)


Obrigado pela atenção.