Un framework middleware pour le serveur HTTP natif de Deno, Deno Deploy, Node.js 16.5 et plus tard, CloudFlare Workers and BUN. Il comprend également un routeur middleware.
Ce framework middleware est inspiré par KOA et Middleware Router inspiré par @ koa / routeur.
Cette lecture se concentre sur la mécanique des API OAK et est destinée à ceux qui connaissent les middleware frameworks JavaScript comme Express et KOA ainsi qu'une compréhension décente de Deno. Si vous ne les connaissez pas, veuillez consulter la documentation sur oakserver.github.io/oak.
Consultez également nos FAQ et le site génial des ressources communautaires.
Note
Les exemples de cette lecture se retirent de main et sont conçus pour le déploiement de Deno CLI ou Deno, ce qui peut ne pas être judicieux à faire lorsque vous cherchez à déployer réellement une charge de travail. Vous voudriez "épingler" à une version particulière qui est compatible avec la version de Deno que vous utilisez et a un ensemble fixe d'API que vous attendez. https://deno.land/x/ prend en charge l'utilisation de balises GIT dans l'URL pour vous diriger vers une version particulière. Donc, pour utiliser la version 13.0.0 de Oak, vous voudriez importer https://deno.land/x/[email protected]/mod.ts .
Oak est disponible sur Deno.land/X et JSR. Pour utiliser à partir de deno.land/x , importez dans un module:
import { Application } from "https://deno.land/x/oak/mod.ts" ;Pour utiliser à partir de JSR, importez dans un module:
import { Application } from "jsr:@oak/oak@14" ;Oak est disponible pour Node.js sur NPM et JSR. Pour utiliser à partir de NPM, installez le package:
npm i @oakserver/oak@14
Puis importer dans un module:
import { Application } from "@oakserver/oak" ;Pour utiliser à partir de JSR, installez le package:
npx jsr i @oak/oak@14
Puis importer dans un module:
import { Application } from "@oak/oak/application" ; Note
Envoyer, les mises à niveau WebSocket et les services sur TLS / HTTPS ne sont pas actuellement pris en charge.
De plus, l'environnement des travailleurs CloudFlare et le contexte d'exécution ne sont pas actuellement exposés au middleware.
Oak est disponible pour les travailleurs de CloudFlare sur JSR. Pour utiliser Ajouter le package à votre projet de travailleur CloudFlare:
npx jsr add @oak/oak@14
Puis importer dans un module:
import { Application } from "@oak/oak/application" ;Contrairement à d'autres temps d'exécution, l'application OAK n'écoute pas les demandes entrantes, mais il gère les demandes de recherche de travailleur. Un exemple de serveur minimal serait:
import { Application } from "@oak/oak/application" ;
const app = new Application ( ) ;
app . use ( ( ctx ) => {
ctx . response . body = "Hello CFW!" ;
} ) ;
export default { fetch : app . fetch } ; Note
Les mises à niveau d'envoi et WebSocket ne sont pas actuellement prises en charge.
Oak est disponible pour BUN sur JSR. Pour utiliser l'installation du package:
bunx jsr i @oak/oak@14
Puis importer dans un module:
import { Application } from "@oak/oak/application" ; Note
Les mises à niveau d'envoi et WebSocket ne sont pas actuellement prises en charge.
La classe Application coordonne la gestion du serveur HTTP, l'exécution du middleware et le traitement des erreurs qui se produisent lors du traitement des demandes. Deux des méthodes sont généralement utilisées: .use() et .listen() . Le middleware est ajouté via la méthode .use() et la méthode .listen() démarrera le serveur et commencera les demandes de traitement avec le middleware enregistré.
Une utilisation de base, répondant à chaque demande avec 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 } ) ;Vous exécuteriez ensuite ce script dans Deno comme:
> deno run --allow-net helloWorld.ts
Pour plus d'informations sur l'exécution du code sous Deno ou des informations sur la façon d'installer la CLI Deno, consultez le manuel Deno.
Le middleware est traité comme une pile, où chaque fonction de middleware peut contrôler le flux de la réponse. Lorsque le middleware est appelé, il a transmis un contexte et une référence à la méthode "suivante" dans la pile.
Un exemple plus complexe:
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 } ) ; Pour fournir un serveur HTTPS, les options app.listen() doivent inclure les options .secure Sécurez définies sur true et fournit également un .certFile et une .keyFile Options.
.handle() Méthode La méthode .handle() est utilisée pour traiter les demandes et recevoir des réponses sans que l'application gère l'aspect du serveur. Cependant, c'est une utilisation avancée et la plupart des utilisateurs voudront utiliser .listen() .
La méthode .handle() accepte jusqu'à trois arguments. Le premier étant un argument Request , et le second étant un argument Deno.Conn . Le troisième argument facultatif est un drapeau pour indiquer si la demande était "sécurisée" dans le sens où elle est originaire d'une connexion TLS au client distant. La méthode résolue avec un objet Response ou undefined si le ctx.respond === true .
Un exemple:
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 ) ;
}
}
} ) ;
}Une instance d'application a également certaines propriétés:
contextState - détermine la méthode utilisée pour créer un état pour un nouveau contexte. Une valeur de "clone" définira l'état comme un clone de l'état de l'application. Une valeur du "prototype" signifie que l'état de l'application sera utilisé comme prototype de l'état du contexte. Une valeur de "alias" signifie que l'état de l'application et l'état du contexte seront une référence au même objet. Une valeur de "empty" initialisera l'état du contexte avec un objet vide.
.jsonBodyReplacer - une fonction de remplacement facultative qui sera appliquée aux corps JSON lors de la formation d'une réponse.
.jsonBodyReviver - Une fonction Reviver facultative qui sera appliquée lors de la lecture des corps JSON dans une demande.
.keys
Clés à utiliser lors de la signature et de la vérification des cookies. La valeur peut être définie sur un tableau de clés et l'instance de KeyStack , ou un objet qui fournit la même interface que KeyStack (par exemple une instance de KeyGrip). Si juste les touches sont passées, Oak gérera les clés via KeyStack qui permet une rotation de clés faciles sans nécessiter de re-signature des valeurs de données.
.proxy
Cela par défaut est false , mais peut être défini via les options de constructeur Application . Ceci est destiné à indiquer que l'application est à l'origine d'un proxy et utilisera X-Forwarded-Proto , X-Forwarded-Host et X-Forwarded-For lors du traitement de la demande, qui devrait fournir des informations plus précises sur la demande.
.state
Un enregistrement de l'état d'application, qui peut être fortement dactylographié en spécifiant un argument générique lors de la construction d'une Application() , ou déduit en passant un objet d'état (par exemple Application({ state }) ).
Le contexte transmis au middleware a plusieurs propriétés:
.app
Une référence à l' Application qui invoque ce middleware.
.cookies
L'instance Cookies pour ce contexte qui vous permet de lire et de définir des cookies.
.request
L'objet Request qui contient des détails sur la demande.
.respond
Détermine si, lorsque le middleware termine le traitement, l'application doit envoyer le .response au client. Si true la réponse sera envoyée, et en cas false la réponse ne sera pas envoyée. La valeur par défaut est true , mais certaines méthodes, comme .upgrade() et .sendEvents() le définiront sur false .
.response
L'objet Response qui sera utilisé pour former la réponse renvoyée au demandeur.
.socket
Cela ne sera undefined si la connexion n'a pas été mise à niveau vers une prise Web. Si la connexion a été mise à niveau, l'interface .socket sera définie.
.state
Un enregistrement de l'état d'application, qui peut être fortement dactylographié en spécifiant un argument générique lors de la construction d'une Application() , ou déduit en passant un objet d'état (par exemple Application({ state }) ).
Le contexte transmis au middleware a certaines méthodes:
.assert()
Fait une affirmation, qui, s'il n'est pas vrai, lance un HTTPError , que la sous-classe est identifiée par le deuxième argument, le message étant le troisième argument.
.send()
Diffuser un fichier sur le client demandeur. Voir le contenu statique ci-dessous pour plus d'informations.
.sendEvents()
Convertissez la connexion actuelle en une réponse d'événement envoyée par serveur et renvoyez un ServerSentEventTarget où les messages et les événements peuvent être diffusés au client. Cela définira .respond sur false .
.throw()
Jette un HTTPError , que la sous-classe est identifiée par le premier argument, avec le message passé comme le second.
.upgrade()
Essayez de mettre à niveau la connexion vers une connexion de socket Web et renvoyez une interface WebSocket . Version précédente de OAK, ce serait une Promise résolue avec une prise Web std/ws .
Contrairement à d'autres cadres middleware, context n'a pas de quantité importante d'alias. Les informations sur la demande ne se trouvent que dans .request et les informations sur la réponse ne se trouvent que dans .response .
Le context.cookies permet d'accéder aux valeurs des cookies dans la demande et permet de définir les cookies dans la réponse. Il sécurise automatiquement les cookies si la propriété .keys est définie sur l'application. Parce que .cookies utilise les API Crypto Web pour signer et valider les cookies, et ces API fonctionnent de manière asynchrone, les API cookies fonctionnent de manière asynchrone. Il a plusieurs méthodes:
.get(key: string, options?: CookieGetOptions): Promise<string | undefined>
Tente de récupérer le cookie de la demande et renvoie la valeur du cookie en fonction de la clé. Si les applications .keys sont définies, le cookie sera vérifié contre une version signée du cookie. Si le cookie est valide, la promesse se résoudra avec la valeur. S'il n'est pas valide, la signature des cookies sera définie pour supprimer la réponse. Si le cookie n'a pas été signé par la clé actuelle, il sera résigné et ajouté à la réponse.
.set(key: string, value: string, options?: CookieSetDeleteOptions): Promise<void>
Définira un cookie dans la réponse en fonction de la clé fournie, de la valeur et de toutes les options. Si les applications .keys sont définies, le cookie sera signé et la signature ajoutée à la réponse. Comme les clés sont signées de manière asynchrone, en attendant la méthode .set() est conseillé.
Le context.request contient des informations sur la demande. Il contient plusieurs propriétés:
.body
Un objet qui donne accès au corps de la demande. Voir ci-dessous pour plus de détails sur l'API du corps de la demande.
.hasBody
Réglé sur true si la demande peut avoir un corps, ou false si ce n'est pas le cas. Il ne valide pas si le corps est soutenu par l'analyseur de corps intégré.
[! Avertissement] Il s'agit d'une API peu fiable. Dans HTTP / 2 dans de nombreuses situations, vous ne pouvez pas déterminer si une demande a un corps ou non, sauf si vous essayez de lire le corps, en raison de la nature en streaming de HTTP / 2. Depuis Deno 1.16.1, pour HTTP / 1.1, Deno reflète également ce comportement. Le seul moyen fiable de déterminer si une demande a un corps ou non est d'essayer de lire le corps.
Il est préférable de déterminer si un corps peut être significatif pour vous avec une méthode donnée, puis essayer de lire et de traiter le corps s'il est significatif dans un contexte donné. Par exemple, GET and HEAD ne devrait jamais avoir de corps, mais des méthodes comme DELETE et OPTIONS peuvent avoir un corps et devraient être traitées de façon conditionnelle si elle est significative pour votre application.
.headers
Les en-têtes de la demande, une instance d' Headers .
.method
Une chaîne qui représente la méthode HTTP pour la demande.
.originalRequest
Désacré en dépréciation sera supprimé dans une future version de chêne.
La demande "brute" NativeServer , qui est une abstraction sur l'objet Request DOM. .originalRequest.request est l'instance Request DOM qui est traitée. Les utilisateurs doivent généralement éviter de les utiliser.
.secure
Un raccourci pour .protocol , renvoyant true si https autrement false .
.source
Lors de l'exécution sous Deno, .source sera défini sur la Request de standard Web source. Lors de l'exécution sous NodeJS, cela ne sera undefined .
.url
Une instance d' URL qui est basée sur l'URL complète de la demande. Ceci est à la place d'avoir des parties de l'URL exposées sur le reste de l'objet de demande.
Et plusieurs méthodes:
.accepts(...types: string[])
Négocie le type de contenu pris en charge par la demande de réponse. Si aucun type de contenu n'est passé, la méthode renvoie un tableau prioritaire de types de contenu acceptés. Si les types de contenu sont passés, le type de contenu le mieux négocié est retourné. Si aucun type de contenu correspond undefined n'est renvoyé.
.acceptsEncodings(...encodings: string[])
Négocie le codage de contenu pris en charge par la demande de réponse. Si aucun encodage n'est passé, la méthode renvoie un tableau prioritaire d'encodages acceptés. Si les encodages sont passés, le codage le plus négocié est retourné. Si aucun encodage ne correspond undefined n'est retourné.
.acceptsLanguages(...languages: string[])
Négocie la langue que le client est capable de comprendre. Où une variante régionale prend la préférence. Si aucun encodage n'est passé, la méthode renvoie un tableau prioritaire de langues comprises. Si les langues sont passées, la langue la plus négociée est retournée. Si aucune langue ne correspond undefined .
Important
Cette API a changé de manière significative dans OAK V13 et plus tard. L'API précédente s'était développée de manière organique depuis que Oak a été créé en 2018 et ne représentait aucune autre API commune. L'API introduite dans la V13 s'aligne mieux sur le moyen Request de l'API de faire face au corps, et devrait être plus familier aux développeurs qui viennent à Oak pour la première fois.
L'API de la demande OAK .body est inspirée par la Request de l'API Fetch mais avec quelques fonctionnalités ajoutées. La request.body du contexte est une instance d'un objet qui fournit plusieurs propriétés:
.has
Réglé sur true si la demande peut avoir un corps, ou false si ce n'est pas le cas. Il ne valide pas si le corps est soutenu par l'analyseur de corps intégré.
[! IMPORTANT] Il s'agit d'une API peu fiable. Dans HTTP / 2 dans de nombreuses situations, vous ne pouvez pas déterminer si une demande a un corps ou non, sauf si vous essayez de lire le corps, en raison de la nature en streaming de HTTP / 2. Depuis Deno 1.16.1, pour HTTP / 1.1, Deno reflète également ce comportement. Le seul moyen fiable de déterminer si une demande a un corps ou non est d'essayer de lire le corps.
Il est préférable de déterminer si un corps peut être significatif pour vous avec une méthode donnée, puis essayer de lire et de traiter le corps s'il est significatif dans un contexte donné. Par exemple, GET and HEAD ne devrait jamais avoir de corps, mais des méthodes comme DELETE et OPTIONS peuvent avoir un corps et devraient être traitées de façon conditionnelle si elle est significative pour votre application.
.stream
Un ReadableStream<Uint8Array> qui permettra à la lecture du corps dans des morceaux Uint8Array . Il s'agit de la propriété .body dans une Request API Fetch.
.used
Réglé sur true si le corps a été utilisé, autrement réglé sur false .
Il a également plusieurs méthodes:
arrayBuffer()
Se résout avec un ArrayBuffer qui contient le contenu du corps, le cas échéant. Convient pour la lecture / manipulation des données binaires.
blob()
Se résout avec un Blob qui contient le contenu du corps. Convient pour la lecture / manipulation des données binaires.
form()
Se résout avec une URLSearchParams qui a été décodée du contenu d'un corps. Ceci est approprié pour un corps avec un type de contenu d' application/x-www-form-urlencoded .
formData()
Se résout avec une instance FormData qui a été décodée à partir du contenu d'un corps. Ceci est approprié pour un corps avec un type de contenu de multipart/form-data .
json()
Se résout avec les données du corps analysées en JSON. Si un jsonBodyReviver a été spécifié dans l'application, il sera utilisé lors de l'analyse du JSON.
text()
Se résout avec une chaîne qui représente le contenu du corps.
type()
Tente de fournir des conseils sur la façon dont le corps est codé qui peut être utilisé pour déterminer la méthode à utiliser pour décoder le corps. La méthode renvoie une chaîne qui représente le type de corps interprété:
| Valeur | Description |
|---|---|
"binary" | Le corps a un type de contenu qui indique des données binaires et le .arrayBuffer() , .blob() ou .stream doit être utilisé pour lire le corps. |
"form" | Le corps est codé sous forme de données de forme et .form() doit être utilisé pour lire le corps. |
"form-data" | Le corps est codé comme une forme en plusieurs parties et .formData() doit être utilisé pour lire le corps. |
"json" | Le corps est codé sous forme de données JSON et .json() doit être utilisé pour lire le corps. |
"text" | Le corps est codé sous forme de texte et .text() doit être utilisé pour lire le corps. |
"unknown" | Soit il n'y a pas de corps, soit il n'a pas été possible de déterminer le type de corps en fonction du type de contenu. |
La méthode .type() prend également un argument facultatif des types de supports personnalisés qui seront utilisés lors de la tentative de déterminer le type de corps. Ceux-ci sont ensuite incorporés dans les types de supports par défaut. La valeur est un objet où la clé est celle de binary , form , form-data , json ou text et la valeur est le type de support approprié dans un format compatible avec le format type-est.
Le context.response contient des informations sur la réponse qui sera renvoyée au demandeur. Il contient plusieurs propriétés:
.body
Le corps de la réponse, qui peut souvent être géré par la manipulation automatique du corps de réponse documentée ci-dessous.
.headers
Une instance Headers qui contient les en-têtes pour la réponse.
.status
Un code Status HTTP qui sera renvoyé avec la réponse. Si cela n'est pas défini avant de répondre, Oak sera par défaut à 200 OK s'il y a un .body , sinon 404 Not Found .
.type
Un type de support ou une extension pour définir l'en-tête Content-Type pour la réponse. Par exemple, vous pouvez fournir txt ou text/plain pour décrire le corps.
Et plusieurs méthodes:
.redirect(url?: string | URL | REDIRECT_BACK, alt?: string | URL)
Une méthode pour simplifier la redirection de la réponse vers une autre URL. Il définira l'en-tête d' Location sur l' url fournie et l'état sur 302 Found (sauf si l'état est déjà un statut 3XX ). L'utilisation de Symbol REDIRECT_BACK comme url indique que l'en-tête Referer dans la demande doit être utilisé comme direction, l' alt étant l'emplacement alternatif si le Referer n'est pas défini. Si ni l' alt ni le Referer ne sont définis, la redirection se produira vers / . Un HTML de base (si le demandeur le prend en charge) ou un corps de texte sera défini en expliquant qu'ils sont redirigés.
.toDomResponse()
Cela convertit l'information que Oak comprend sur la réponse à la Response API Fetch. Cela finalisera la réponse, ce qui entraînera une nouvelle tentative de modification de la réponse à lancer. Ceci est destiné à être utilisé en interne dans le chêne pour pouvoir répondre aux demandes.
.with(response: Response) et .with(body?: BodyInit, init?: ResponseInit)
Cela définit la réponse à une Response standard Web. Notez que cela ignorera / remplacera tout autre ensemble d'informations sur la réponse par d'autres middleware, y compris des choses comme les en-têtes ou les cookies à définir.
Lorsque le Content-Type de réponse n'est pas défini dans les en-têtes du .response , Oak essaiera automatiquement de déterminer le Content-Type approprié. Il examinera d'abord .response.type . S'il est attribué, il essaiera de résoudre le type de support approprié en fonction du traitement de la valeur de .type comme type de support, soit de la résolution du type de support en fonction d'une extension. Par "text/html" , si .type Le Content-Type "html"
Si. Le .type .response.body Si la valeur est une string , Oak vérifiera si la chaîne ressemble à HTML, si c'est le cas, Content-Type sera défini sur text/html sinon il sera défini sur text/plain . Si la valeur est un objet, autre que Uint8Array , un Deno.Reader , ou null , l'objet sera transmis à JSON.stringify() et le Content-Type sera défini sur application/json .
Si le type de corps est un nombre, un bigint ou un symbole, il sera contraint à une chaîne et traité comme du texte.
Si la valeur du corps est une fonction, la fonction sera appelée sans arguments. Si la valeur de retour de la fonction est prometteuse comme, ce sera attendu et que la valeur résolu sera traitée comme ci-dessus. Si la valeur n'est pas prometteuse, elle sera traitée comme ci-dessus.
La méthode d'application .listen() est utilisée pour ouvrir le serveur, commencer à écouter les demandes et traiter le middleware enregistré pour chaque demande. Cette méthode renvoie une promesse à la fermeture du serveur.
Une fois le serveur ouvert, avant de commencer les demandes de traitement, l'application licenciera un événement "listen" , qui peut être écouté via la méthode .addEventListener() . Par exemple:
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 } ) ;Si vous souhaitez fermer l'application, l'application prend en charge l'option d'un signal d'abandon. Voici un exemple d'utilisation du signal:
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 shutdownLe middleware peut être utilisé pour gérer d'autres erreurs avec le middleware. En attente d'autres middleware à exécuter lors des erreurs de piégeage. Donc, si vous aviez une erreur de gestion des middleware qui fournit une réponse bien gérée aux erreurs fonctionnerait comme ceci:
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 ;
}
}
} ) ; Les exceptions de middleware non apprises seront prises par l'application. Application étend le Global EventTarget dans Deno, et lorsque des erreurs non apprises se produisent dans le middleware ou l'envoi de réponses, un EventError sera expédié à l'application. Pour écouter ces erreurs, vous ajouteriez un gestionnaire d'événements à l'instance d'application:
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 } ) ; La classe Router produit du middleware qui peut être utilisée avec une Application pour activer le routage en fonction du chemin d'accès de la demande.
L'exemple suivant sert un service reposant d'une carte de livres, où http://localhost:8000/book/ renverra un tableau de livres et http://localhost:8000/book/1 retournerait le livre avec 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 } ) ; Un itinéraire passé est converti en une expression régulière en utilisant le chemin à regexp, ce qui signifie que les paramètres exprimés dans le motif seront convertis. path-to-regexp a une utilisation avancée qui peut créer des modèles complexes qui peuvent être utilisés pour la correspondance. Consultez la documentation de cette bibliothèque si vous avez des cas d'utilisation avancés.
Dans la plupart des cas, le type de context.params est automatiquement déduit de la chaîne de modèle de chemin via la magie de type TypeScript. Dans les scénarios plus complexes, cela pourrait ne pas donner le résultat correct cependant. Dans ce cas, vous pouvez remplacer le type avec router.get<RouteParams> , où RouteParams est le type explicite pour context.params .
Les routeurs de nidification sont soutenus. L'exemple suivant répond à http://localhost:8000/forums/oak/posts et 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 } ) ; La fonction send() est conçue pour servir le contenu statique dans le cadre d'une fonction middleware. Dans l'utilisation la plus simple, une racine est fournie et les demandes fournies à la fonction sont remplies avec des fichiers du système de fichiers local par rapport à la racine du chemin demandé.
Une utilisation de base ressemblerait à ceci:
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() prend en charge automatiquement des fonctionnalités telles que la fourniture ETag et les en-têtes Last-Modified dans la réponse ainsi que le traitement des en-têtes If-None-Match et If-Modified-Since dans la demande. Cela signifie que lorsque vous servez du contenu statique, les clients pourront compter sur leurs versions en cache d'actifs au lieu de les redémarrer.
La méthode send() prend automatiquement prend en charge la génération d'un en-tête ETag pour les actifs statiques. L'en-tête permet au client de déterminer s'il a besoin de redémarrer un actif ou non, mais il peut être utile de calculer ETag S pour d'autres scénarios.
Il existe une fonction de middleware qui évalue le context.reponse.body et détermine s'il peut créer un en-tête ETag pour ce type de corps, et si c'est le cas définit l'en-tête ETag sur la réponse. L'utilisation de base ressemblerait à ceci:
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 applicationIl existe également une fonction qui récupère une entité pour un contexte donné basé sur ce qu'il est logique de lire dans la mémoire qui peut être transmis au calcul ETAG qui fait partie de la bibliothèque 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() Si vous migrez de Deno.serve() ou du code d'adaptation conçu pour Request et Response de l'API Fetch Standard Web, il existe quelques fonctionnalités de chêne pour vous aider.
ctx.request.source Lors de l'exécution sous Deno, cela sera défini sur une Request API Fetch, donnant un accès direct à la demande d'origine.
ctx.response.with() Cette méthode acceptera une Response API Fetch ou créera une nouvelle réponse basée sur la BodyInit et ResponseInit fournies. Cela finalisera également la réponse et ignore tout ce qui pourrait avoir été réglé sur le chêne .response .
middleware/serve#serve() et middelware/serve#route() Ces deux générateurs de middleware peuvent être utilisés pour adapter du code qui fonctionne plus comme le Deno.serve() en ce qu'il fournit une Request API Fetch et s'attend à ce que le gestionnaire se résout avec une Response API Fetch.
Un exemple d'utilisation de serve() avec 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 ( ) ; Et une solution similaire fonctionne avec route() où le contexte contient les informations sur le routeur, comme les paramètres:
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 ( ) ; Le mod.ts exporte un objet nommé testing qui contient certains services publics pour tester le middleware OAK que vous pourriez créer. Voir les tests avec Oak pour plus d'informations.
Il existe plusieurs modules qui sont directement adaptés des autres modules. Ils ont conservé leurs licences individuelles et leurs droits d'auteur. Tous les modules, y compris ceux directement adaptés, sont autorisés sous la licence MIT.
Tous les travaux supplémentaires sont Copyright 2018 - 2024 The Oak Auteurs. Tous droits réservés.