Uma estrutura de middleware para o servidor HTTP nativo de Deno, Deno implantar, Node.js 16.5 e posterior, Cloudflare Workers e Bun. Ele também inclui um roteador de middleware.
Esta estrutura de middleware é inspirada no KOA e no roteador de middleware inspirado no @koa/roteador.
Este readme se concentra na mecânica das APIs de carvalho e se destina a aqueles que estão familiarizados com as estruturas de middleware JavaScript como Express e Koa, bem como um entendimento decente de Deno. Se você não estiver familiarizado com isso, confira a documentação no Oakserver.github.io/oak.
Além disso, confira nossas perguntas frequentes e o site de recursos da comunidade.
Observação
Os exemplos desta readme de leitura da main e são projetados para Deno CLI ou Deno implantando, o que pode não fazer sentido quando você procura realmente implantar uma carga de trabalho. Você gostaria de "PIN" em uma versão específica que é compatível com a versão do deno que você está usando e possui um conjunto fixo de APIs que você esperaria. https://deno.land/x/ suporta o uso de tags Git no URL para direcioná -lo em uma versão específica. Então, para usar a versão 13.0.0 do Oak, você deseja importar https://deno.land/x/[email protected]/mod.ts .
O Oak está disponível em deno.land/x e JSR. Para usar em deno.land/x , importe para um módulo:
import { Application } from "https://deno.land/x/oak/mod.ts" ;Para usar do JSR, importe para um módulo:
import { Application } from "jsr:@oak/oak@14" ;O Oak está disponível para Node.js no NPM e JSR. Para usar no NPM, instale o pacote:
npm i @oakserver/oak@14
E depois importe para um módulo:
import { Application } from "@oakserver/oak" ;Para usar no JSR, instale o pacote:
npx jsr i @oak/oak@14
E depois importe para um módulo:
import { Application } from "@oak/oak/application" ; Observação
Enviar, atualizações do WebSocket e servir sobre TLS/HTTPS não são suportados no momento.
Além disso, o ambiente do trabalhador CloudFlare e o contexto de execução não estão atualmente expostos ao middleware.
O Oak está disponível para os trabalhadores do CloudFlare na JSR. Para usar, adicione o pacote ao seu projeto CloudFlare Worker:
npx jsr add @oak/oak@14
E depois importe para um módulo:
import { Application } from "@oak/oak/application" ;Ao contrário de outros tempos de execução, o aplicativo Oak não ouve para solicitações de entrada, em vez disso, ele lida com solicitações de busca de trabalhadores. Um servidor de exemplo mínimo seria:
import { Application } from "@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello CFW!" ;
} ) ;
export default { fetch : app . fetch } ; Observação
As atualizações de envio e webSocket não são suportadas no momento.
O Oak está disponível para BUN no JSR. Para usar a instalação do pacote:
bunx jsr i @oak/oak@14
E depois importe para um módulo:
import { Application } from "@oak/oak/application" ; Observação
As atualizações de envio e webSocket não são suportadas no momento.
A classe Application coordena o gerenciamento do servidor HTTP, executando o middleware e os erros de manuseio que ocorrem ao processamento de solicitações. Dois dos métodos são geralmente usados: .use() e .listen() . O middleware é adicionado através do método .use() e do método .listen() iniciarão o servidor e iniciarão as solicitações de processamento com o middleware registrado.
Um uso básico, respondendo a todos os pedidos com o Hello World! :
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
await app . listen ( { port : 8000 } ) ;Você então executaria este script em deno como:
> deno run --allow-net helloWorld.ts
Para obter mais informações sobre a execução do código sob Deno, ou informações sobre como instalar a CLI deno, consulte o Manual deno.
O middleware é processado como uma pilha, onde cada função de middleware pode controlar o fluxo da resposta. Quando o middleware é chamado, ele é passado um contexto e referência ao método "próximo" na pilha.
Um exemplo mais complexo:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
// Logger
app . use ( async ( ctx , next ) => {
await next ( ) ;
const rt = ctx . response . headers . get ( "X-Response-Time" ) ;
console . log ( ` ${ ctx . request . method } ${ ctx . request . url } - ${ rt } ` ) ;
} ) ;
// Timing
app . use ( async ( ctx , next ) => {
const start = Date . now ( ) ;
await next ( ) ;
const ms = Date . now ( ) - start ;
ctx . response . headers . set ( "X-Response-Time" , ` ${ ms } ms` ) ;
} ) ;
// Hello World!
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
await app . listen ( { port : 8000 } ) ; Para true um servidor HTTPS, as opções app.listen() .certFile .keyFile as opções .secure
.handle() Método O método .handle() é usado para processar solicitações e receber respostas sem que o aplicativo gerencie o aspecto do servidor. Porém, isso é um uso avançado e a maioria dos usuários desejará usar .listen() .
O método .handle() aceita até três argumentos. O primeiro é um argumento Request , e o segundo é um argumento Deno.Conn . O terceiro argumento opcional é um sinalizador para indicar se a solicitação era "segura" no sentido de que se originou de uma conexão TLS com o cliente remoto. O método foi resolvido com um objeto Response ou undefined se o ctx.respond === true .
Um exemplo:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello World!" ;
} ) ;
const listener = Deno . listen ( { hostname : "localhost" , port : 8000 } ) ;
for await ( const conn of listener ) {
( async ( ) => {
const requests = Deno . serveHttp ( conn ) ;
for await ( const { request , respondWith } of requests ) {
const response = await app . handle ( request , conn ) ;
if ( response ) {
respondWith ( response ) ;
}
}
} ) ;
}Uma instância do aplicativo também possui algumas propriedades:
contextState - determina o método usado para criar estado para um novo contexto. Um valor de "clone" definirá o estado como um clone do estado do aplicativo. Um valor de "prototype" significa que o estado do aplicativo será usado como protótipo do estado do contexto. Um valor de "alias" significa que o estado do aplicativo e o estado do contexto serão uma referência ao mesmo objeto. Um valor de "empty" inicializará o estado do contexto com um objeto vazio.
.jsonBodyReplacer - Uma função de substituição opcional que será aplicada aos corpos JSON ao formar uma resposta.
.jsonBodyReviver - Uma função de reviver opcional que será aplicada ao ler os corpos JSON em uma solicitação.
.keys
Chaves a serem usadas ao assinar e verificar cookies. O valor pode ser definido como uma matriz de chaves, e a instância do KeyStack , ou um objeto que fornece a mesma interface que KeyStack (por exemplo, uma instância do KeyGrip). Se apenas as teclas forem passadas, o Oak gerenciará as chaves via KeyStack , que permite uma rotação de chaves fácil sem a necessidade de assinatura dos valores de dados.
.proxy
Isso padrão é false , mas pode ser definido através das opções de construtor Application . Isso se destina a indicar que o aplicativo está por trás de um proxy e usará X-Forwarded-Proto , X-Forwarded-Host e X-Forwarded-For o processamento da solicitação, que deve fornecer informações mais precisas sobre a solicitação.
.state
Um registro do estado do aplicativo, que pode ser fortemente digitado especificando um argumento genérico ao construir um Application() ou inferido pela aprovação de um objeto de estado (por exemplo, Application({ state }) ).
O contexto passado para o middleware tem várias propriedades:
.app
Uma referência ao Application que está invocando este middleware.
.cookies
A instância Cookies para este contexto que permite ler e definir cookies.
.request
O objeto Request que contém detalhes sobre a solicitação.
.respond
Determina se, quando o middleware termina o processamento, o aplicativo deve enviar a .response ao cliente. Se true a resposta será enviada e, se false a resposta não será enviada. O padrão é true , mas certos métodos, como .upgrade() e .sendEvents() o definirão como false .
.response
O objeto Response que será usado para formar a resposta enviada de volta ao solicitante.
.socket
Isso será undefined se a conexão não tiver sido atualizada para um soquete da Web. Se a conexão tiver sido atualizada, a interface .socket será definida.
.state
Um registro do estado do aplicativo, que pode ser fortemente digitado especificando um argumento genérico ao construir um Application() ou inferido pela aprovação de um objeto de estado (por exemplo, Application({ state }) ).
O contexto passado para o middleware tem alguns métodos:
.assert()
Faz uma afirmação, que, se não for verdade, lança um HTTPError , que a subclasse é identificada pelo segundo argumento, com a mensagem sendo o terceiro argumento.
.send()
Transmitir um arquivo para o cliente solicitante. Veja o conteúdo estático abaixo para obter mais informações.
.sendEvents()
Converta a conexão atual em uma resposta de evento enviada ao servidor e retorne um ServerSentEventTarget , onde mensagens e eventos podem ser transmitidos para o cliente. Isso definirá .respond RELEITO PARA false .
.throw()
Joga um HTTPError , que a subclasse é identificada pelo primeiro argumento, com a mensagem sendo passada como a segunda.
.upgrade()
Tente atualizar a conexão com uma conexão de soquete da Web e retorne uma interface WebSocket . Versão anterior do Oak, essa seria uma Promise resolvendo com um soquete da Web std/ws .
Ao contrário de outras estruturas de middleware, context não possui uma quantidade significativa de aliases. As informações sobre a solicitação estão localizadas apenas no .request e as informações sobre a resposta estão localizadas apenas em .response .
O context.cookies permite o acesso aos valores dos cookies na solicitação e permite que os cookies sejam definidos na resposta. Ele protege automaticamente os cookies se a propriedade .keys estiver definida no aplicativo. Como .cookies usa as APIs da Web Crypto para assinar e validar cookies, e essas APIs funcionam de maneira assíncrona, as APIs de cookie funcionam de maneira assíncrona. Tem vários métodos:
.get(key: string, options?: CookieGetOptions): Promise<string | undefined>
Tentativas de recuperar o cookie da solicitação e retorna o valor do cookie com base na chave. Se os aplicativos .keys estiverem definidos, o cookie será verificado contra uma versão assinada do cookie. Se o cookie for válido, a promessa será resolvida com o valor. Se for inválido, a assinatura do cookie será definida para excluir a resposta. Se o cookie não foi assinado pela chave atual, ele será resignado e adicionado à resposta.
.set(key: string, value: string, options?: CookieSetDeleteOptions): Promise<void>
Definirá um cookie na resposta com base na chave, valor e opções fornecidas. Se os aplicativos .keys estiverem definidos, o cookie será assinado e a assinatura adicionada à resposta. À medida que as chaves são assinadas de forma assíncrona, aguardando o método .set() .
O context.request contém informações sobre a solicitação. Ele contém várias propriedades:
.body
Um objeto que fornece acesso ao corpo da solicitação. Veja abaixo os detalhes sobre a API do corpo de solicitação.
.hasBody
Defina como true se a solicitação puder ter um corpo, ou false se não o fizer. No entanto, ele não valida se o corpo for apoiado pelo analisador de corpo embutido.
[! Aviso] Esta é uma API não confiável. Em http/2 em muitas situações, você não pode determinar se uma solicitação tem um corpo ou não, a menos que tente ler o corpo, devido à natureza de streaming do HTTP/2. Até o deno 1.16.1, para http/1.1, o deno também reflete esse comportamento. A única maneira confiável de determinar se uma solicitação tem um corpo ou não é tentar ler o corpo.
É melhor determinar se um corpo pode ser significativo para você com um determinado método e, em seguida, tentar ler e processar o corpo se for significativo em um determinado contexto. Por exemplo, GET and HEAD nunca deve ter um corpo, mas métodos como DELETE e OPTIONS podem ter um corpo e devem ter seu corpo processado condicionalmente se for significativo para o seu aplicativo.
.headers
Os cabeçalhos para o pedido, uma instância dos Headers .
.method
Uma string que representa o método HTTP para a solicitação.
.originalRequest
Depreciado Isso será removido em uma versão futura do Oak.
A solicitação NativeServer "RAW", que é uma abstração sobre o objeto Request DOM. .originalRequest.request é a instância Request DOM que está sendo processada. Os usuários geralmente devem evitar usá -los.
.secure
Um atalho para .protocol , retornando true se https, caso contrário, false .
.source
Ao executar com o deno, .source será definido para a Request padrão da web de origem. Ao executar com o NodeJS, isso será undefined .
.url
Uma instância da URL que é baseada no URL completo para a solicitação. Isso está no lugar de ter partes do URL expostas no restante do objeto de solicitação.
E vários métodos:
.accepts(...types: string[])
Negocia o tipo de conteúdo suportado pela solicitação de resposta. Se nenhum tipo de conteúdo for passado, o método retornará uma matriz priorizada de tipos de conteúdo aceitos. Se os tipos de conteúdo forem aprovados, o melhor tipo de conteúdo negociado será retornado. Se nenhuma correspondência de tipo de conteúdo undefined for retornada.
.acceptsEncodings(...encodings: string[])
Negocia o conteúdo codificando suportado pela solicitação de resposta. Se nenhuma codificação for passada, o método retornará uma matriz priorizada de codificações aceitas. Se as codificações forem aprovadas, a melhor codificação negociada será devolvida. Se nenhuma correspondência de codificação undefined for devolvida.
.acceptsLanguages(...languages: string[])
Negocia o idioma que o cliente é capaz de entender. Onde uma variante de localidade tem preferência. Se nenhuma codificação for passada, o método retornará uma matriz priorizada de idiomas compreendidos. Se os idiomas forem aprovados, o melhor idioma negociado será devolvido. Se nenhuma correspondência de idiomas undefined for devolvida.
Importante
Esta API mudou significativamente no Oak V13 e mais tarde. A API anterior cresceu organicamente desde que o Oak foi criado em 2018 e não representou nenhuma outra API comum. A API introduzida no V13 se alinha melhor à maneira de Request a API de lidar com o corpo e deve ser mais familiar para os desenvolvedores que chegam a Oak pela primeira vez.
A API para a solicitação de carvalho .body O corpo é inspirado na Request da API da busca, mas com alguns adicionais funcionalidades. A request.body do contexto.Body é uma instância de um objeto que fornece várias propriedades:
.has
Defina como true se a solicitação puder ter um corpo, ou false se não o fizer. No entanto, ele não valida se o corpo for apoiado pelo analisador de corpo embutido.
[! IMPORTANTE] Esta é uma API não confiável. Em http/2 em muitas situações, você não pode determinar se uma solicitação tem um corpo ou não, a menos que tente ler o corpo, devido à natureza de streaming do HTTP/2. Até o deno 1.16.1, para http/1.1, o deno também reflete esse comportamento. A única maneira confiável de determinar se uma solicitação tem um corpo ou não é tentar ler o corpo.
É melhor determinar se um corpo pode ser significativo para você com um determinado método e, em seguida, tentar ler e processar o corpo se for significativo em um determinado contexto. Por exemplo, GET and HEAD nunca deve ter um corpo, mas métodos como DELETE e OPTIONS podem ter um corpo e devem ter seu corpo processado condicionalmente se for significativo para o seu aplicativo.
.stream
Um ReadableStream<Uint8Array> que permitirá a leitura do corpo em pedaços Uint8Array . Esta é a Request .body
.used
Defina como true se o corpo tiver sido usado, caso contrário, definido como false .
Ele também tem vários métodos:
arrayBuffer()
Resolve com um ArrayBuffer que contém o conteúdo do corpo, se houver. Adequado para leitura/manuseio dados binários.
blob()
Resolve com uma Blob que contém o conteúdo do corpo. Adequado para leitura/manuseio dados binários.
form()
Resolve com um URLSearchParams que foi decodificado do conteúdo de um corpo. Isso é apropriado para um corpo com um tipo de conteúdo de application/x-www-form-urlencoded .
formData()
Resolve com uma instância FormData que foi decodificada do conteúdo de um corpo. Isso é apropriado para um corpo com um tipo de conteúdo de multipart/form-data .
json()
Resolve com os dados do corpo analisado como JSON. Se um jsonBodyReviver tiver sido especificado no aplicativo, ele será usado ao analisar o JSON.
text()
Resolve com uma corda que representa o conteúdo do corpo.
type()
Tentativas de fornecer orientação de como o corpo é codificado, que pode ser usado para determinar qual método usar para decodificar o corpo. O método retorna uma string que representa o tipo de corpo interpretado:
| Valor | Descrição |
|---|---|
"binary" | O corpo possui um tipo de conteúdo que indica dados binários e o .arrayBuffer() , .blob() ou .stream devem ser usados para ler o corpo. |
"form" | O corpo é codificado como dados de formulário e .form() devem ser usados para ler o corpo. |
"form-data" | O corpo é codificado como uma forma de várias partes e .formData() deve ser usado para ler o corpo. |
"json" | O corpo é codificado como dados JSON e .json() devem ser usados para ler o corpo. |
"text" | O corpo é codificado como texto e .text() devem ser usados para ler o corpo. |
"unknown" | Ou não há corpo ou não foi possível determinar o tipo de corpo com base no tipo de conteúdo. |
O método .type() também leva um argumento opcional de tipos de mídia personalizados que serão usados ao tentar determinar o tipo de corpo. Estes são então incorporados aos tipos de mídia padrão. O valor é um objeto em que a chave é de binary , form , form-data , json ou text e o valor é o tipo de mídia apropriado em um formato compatível com o formato Type-IS.
O context.response contém informações sobre a resposta que será enviada de volta ao solicitante. Ele contém várias propriedades:
.body
O corpo da resposta, que geralmente pode ser tratado pelo manuseio automático do corpo de resposta documentado abaixo.
.headers
Uma instância Headers que contém os cabeçalhos para a resposta.
.status
Um código Status HTTP que será enviado de volta com a resposta. Se isso não estiver definido antes de responder, o Oak padrão para 200 OK se houver um .body , caso contrário, 404 Not Found .
.type
Um tipo de mídia ou extensão para definir o cabeçalho Content-Type para a resposta. Por exemplo, você pode fornecer txt ou text/plain para descrever o corpo.
E vários métodos:
.redirect(url?: string | URL | REDIRECT_BACK, alt?: string | URL)
Um método para simplificar o redirecionamento da resposta para outro URL. Ele definirá o cabeçalho Location para o url fornecido e o status para 302 Found (a menos que o status já seja um status 3XX ). O uso do símbolo REDIRECT_BACK como o url indica que o cabeçalho Referer na solicitação deve ser usado como direção, sendo o alt o local alternativo se o Referer não estiver definido. Se nem o alt nem o Referer estiverem definidos, o redirecionamento ocorrerá para / . Um HTML básico (se o solicitante suportar) ou um corpo de texto será definido explicando que eles estão sendo redirecionados.
.toDomResponse()
Isso converte a informação Oak entende sobre a resposta à Response da API busca. Isso finalizará a resposta, resultando em qualquer tentativa adicional de modificar a resposta para lançar. Destina -se a ser usado internamente no Oak para poder responder às solicitações.
.with(response: Response) e .with(body?: BodyInit, init?: ResponseInit)
Isso define a resposta a uma Response padrão da Web. Observe que isso ignorará/substituirá qualquer outra informação definida sobre a resposta de outro middleware, incluindo coisas como cabeçalhos ou cookies a serem definidos.
Quando o Content-Type da resposta não estiver definido nos cabeçalhos do .response , o Oak tentará automaticamente determinar o Content-Type apropriado. Primeiro, ele analisará .response.type . Se atribuído, tentará resolver o tipo de mídia apropriado com base no tratamento do valor do .type como o tipo de mídia ou resolvendo o tipo de mídia com base em uma extensão. Por exemplo, se .type foi definido como "html" , o Content-Type será definido como "text/html" .
Se .type não estiver definido com um valor, o Oak inspecionará o valor de .response.body . Se o valor for uma string , o Oak verificará se a sequência se parece com HTML, se for o tipo, Content-Type será definido como text/html caso contrário, será definido como text/plain . Se o valor for um objeto, além de um Uint8Array , um Deno.Reader ou null , o objeto será passado para JSON.stringify() e o Content-Type será definido como application/json .
Se o tipo de corpo for um número, bigint ou símbolo, ele será coagido a uma corda e tratado como texto.
Se o valor do corpo for uma função, a função será chamada sem argumentos. Se o valor de retorno da função for prometido, isso será aguardado e o valor resolvido será processado como acima. Se o valor não for prometido, ele será processado como acima.
O método do aplicativo .listen() é usado para abrir o servidor, começar a ouvir solicitações e processar o middleware registrado para cada solicitação. Este método retorna uma promessa quando o servidor fecha.
Depois que o servidor estiver aberto, antes de iniciar o processamento de solicitações, o aplicativo demitirá um evento "listen" , que pode ser ouvido pelo método .addEventListener() . Por exemplo:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . addEventListener ( "listen" , ( { hostname , port , secure } ) => {
console . log (
`Listening on: ${ secure ? "https://" : "http://" } ${
hostname ?? "localhost"
} : ${ port } ` ,
) ;
} ) ;
// register some middleware
await app . listen ( { port : 80 } ) ;Se você deseja fechar o aplicativo, o aplicativo suporta a opção de um sinal de aborto. Aqui está um exemplo de uso do sinal:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
const controller = new AbortController ( ) ;
const { signal } = controller ;
// Add some middleware using `app.use()`
const listenPromise = app . listen ( { port : 8000 , signal } ) ;
// In order to close the server...
controller . abort ( ) ;
// Listen will stop listening for requests and the promise will resolve...
await listenPromise ;
// and you can do something after the close to shutdownO middleware pode ser usado para lidar com outros erros com o middleware. Aguardando outro middleware para executar enquanto os erros de captura funcionam. Portanto, se você tivesse um middleware de manuseio de erros que fornece uma resposta bem gerenciada a erros funcionaria assim:
import { Application } from "jsr:@oak/oak/application" ;
import { isHttpError } from "jsr:@oak/commons/http_errors" ;
import { Status } from "jsr:@oak/commons/status" ;
const app = new Application ( ) ;
app . use ( async ( ctx , next ) => {
try {
await next ( ) ;
} catch ( err ) {
if ( isHttpError ( err ) ) {
switch ( err . status ) {
case Status . NotFound :
// handle NotFound
break ;
default :
// handle other statuses
}
} else {
// rethrow if you can't handle the error
throw err ;
}
}
} ) ; Exceções de middleware não capturadas serão capturadas pelo aplicativo. Application estende o Global EventTarget em Deno e, quando erros não capturados ocorrem no middleware ou no envio de respostas, um EventError será despachado para o aplicativo. Para ouvir esses erros, você adicionaria um manipulador de eventos à instância do aplicativo:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . addEventListener ( "error" , ( evt ) => {
// Will log the thrown error to the console.
console . log ( evt . error ) ;
} ) ;
app . use ( ( ctx ) => {
// Will throw a 500 on every request.
ctx . throw ( 500 ) ;
} ) ;
await app . listen ( { port : 80 } ) ; A classe Router produz middleware que pode ser usada com um Application para ativar o roteamento com base no nome do caminho da solicitação.
O exemplo a seguir serve um serviço repousante de um mapa de livros, onde http://localhost:8000/book/ retornará uma variedade de livros e http://localhost:8000/book/1 retornaria o livro com id "1" :
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
const books = new Map < string , any > ( ) ;
books . set ( "1" , {
id : "1" ,
title : "The Hound of the Baskervilles" ,
author : "Conan Doyle, Arthur" ,
} ) ;
const router = new Router ( ) ;
router
. get ( "/" , ( context ) => {
context . response . body = "Hello world!" ;
} )
. get ( "/book" , ( context ) => {
context . response . body = Array . from ( books . values ( ) ) ;
} )
. get ( "/book/:id" , ( context ) => {
if ( books . has ( context ?. params ?. id ) ) {
context . response . body = books . get ( context . params . id ) ;
}
} ) ;
const app = new Application ( ) ;
app . use ( router . routes ( ) ) ;
app . use ( router . allowedMethods ( ) ) ;
await app . listen ( { port : 8000 } ) ; Uma rota aprovada é convertida em uma expressão regular usando caminho para regexp, o que significa que os parâmetros expressos no padrão serão convertidos. path-to-regexp possui um uso avançado que pode criar padrões complexos que podem ser usados para correspondência. Confira a documentação dessa biblioteca se você tiver casos de uso avançado.
Na maioria dos casos, o tipo de context.params é inferido automaticamente da sequência do modelo de caminho através da magia do TypeScript. Em cenários mais complexos, isso pode não produzir o resultado correto, no entanto. Nesse caso, você pode substituir o tipo pelo router.get<RouteParams> , onde RouteParams é o tipo explícito para context.params .
Os roteadores de nidificação são suportados. O exemplo a seguir responde a http://localhost:8000/forums/oak/posts e http://localhost:8000/forums/oak/posts/nested-routers .
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
const posts = new Router ( )
. get ( "/" , ( ctx ) => {
ctx . response . body = `Forum: ${ ctx . params . forumId } ` ;
} )
. get ( "/:postId" , ( ctx ) => {
ctx . response . body =
`Forum: ${ ctx . params . forumId } , Post: ${ ctx . params . postId } ` ;
} ) ;
const forums = new Router ( ) . use (
"/forums/:forumId/posts" ,
posts . routes ( ) ,
posts . allowedMethods ( ) ,
) ;
await new Application ( ) . use ( forums . routes ( ) ) . listen ( { port : 8000 } ) ; A função send() foi projetada para servir conteúdo estático como parte de uma função de middleware. No uso mais direto, uma raiz é fornecida e as solicitações fornecidas à função são cumpridas com arquivos do sistema de arquivos local em relação à raiz do caminho solicitado.
Um uso básico seria algo assim:
import { Application } from "jsr:@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( async ( context , next ) => {
try {
await context . send ( {
root : ` ${ Deno . cwd ( ) } /examples/static` ,
index : "index.html" ,
} ) ;
} catch {
await next ( ) ;
}
} ) ;
await app . listen ( { port : 8000 } ) ; send() suporta recursos automaticamente como fornecer os cabeçalhos ETag e Last-Modified na resposta, além de processar os cabeçalhos de If-None-Match e If-Modified-Since na solicitação. Isso significa que, ao servir o conteúdo estático, os clientes poderão confiar em suas versões em cache de ativos em vez de baixá-los novamente.
O método send() suporta automaticamente a geração de um cabeçalho ETag para ativos estáticos. O cabeçalho permite que o cliente determine se ele precisa fazer o download de um ativo ou não, mas pode ser útil calcular ETag S para outros cenários.
ETag ETag função de middleware que avalia o context.reponse.body . O uso básico seria algo assim:
import { Application } from "jsr:@oak/oak/application" ;
import { factory } from "jsr:@oak/oak/etag" ;
const app = new Application ( ) ;
app . use ( factory ( ) ) ;
// ... other middleware for the applicationHá também uma função que recupera uma entidade para um determinado contexto com base no que é lógico ler na memória que pode ser transmitido ao ETAG Calcule que faz parte da biblioteca Deno STD:
import { Application } from "jsr:@oak/oak/application" ;
import { getEntity } from "jsr:@oak/oak/etag" ;
import { calculate } from "jsr:@std/http/etag" ;
const app = new Application ( ) ;
// The context.response.body has already been set...
app . use ( async ( ctx ) => {
const entity = await getEntity ( ctx ) ;
if ( entity ) {
const etag = await calculate ( entity ) ;
}
} ) ; Deno.serve() Migração Se você estiver migrando de Deno.serve() ou adaptando código projetado para a Request e Response da API de busca padrão da Web, existem alguns recursos de carvalho para ajudar.
ctx.request.source Ao executar com o Deno, isso será definido como uma Request de API buscar, fornecendo acesso direto à solicitação original.
ctx.response.with() Este método aceitará uma Response da API buscar ou criará uma nova resposta com base na BodyInit e ResponseInit fornecidas. Isso também finalizará a resposta e ignora qualquer coisa que possa ter sido definida no Oak .response .
middleware/serve#serve() e middelware/serve#route() Esses dois geradores de middleware podem ser usados para adaptar o código que opera mais como o Deno.serve() pois fornece uma Request de API buscar e espera que o manipulador resolva com uma Response da API buscar.
Um exemplo de uso de serve() com Application.prototype.use() :
import { Application } from "jsr:@oak/oak/application" ;
import { serve } from "jsr:@oak/oak/serve" ;
const app = new Application ( ) ;
app . use ( serve ( ( req , ctx ) => {
console . log ( req . url ) ;
return new Response ( "Hello world!" ) ;
} ) ) ;
app . listen ( ) ; E uma solução semelhante funciona com route() em que o contexto contém as informações sobre o roteador, como os parâmetros:
import { Application } from "jsr:@oak/oak/application" ;
import { Router } from "jsr:@oak/oak/router" ;
import { route } from "jsr:@oak/oak/serve" ;
const app = new Application ;
const router = new Router ( ) ;
router . get ( "/books/:id" , route ( ( req , ctx ) => {
console . log ( ctx . params . id ) ;
return Response . json ( { title : "hello world" , id : ctx . params . id } ) ;
} ) ) ;
app . use ( router . routes ( ) ) ;
app . listen ( ) ; O mod.ts exporta um objeto chamado testing que contém alguns utilitários para testar o middleware de carvalho que você pode criar. Consulte o teste com carvalho para obter mais informações.
Existem vários módulos que são diretamente adaptados de outros módulos. Eles preservaram suas licenças e direitos autorais individuais. Todos os módulos, incluindo os adaptados diretamente estão licenciados sob a licença do MIT.
Todo o trabalho adicional é Copyright 2018 - 2024 The Oak Authors. Todos os direitos reservados.