DocsGestionnaires et erreurs

Pages d'erreur par dossier

Un dossier peut répondre à ses propres erreurs : un blog avec un 404 dans ses propres mots, un espace privé qui propose le formulaire de connexion au lieu d'un simple 401. Le reste du site conserve la page qu'il possédait déjà.

Cette page ajoute un de ces fichiers et affiche la réponse.

La règle

Le fichier le plus profond qui correspond aux réponses de l'URL. Tout le reste reste tel quel : les mêmes codes d'état, JSON pour un client API et la page intégrée une fois qu'aucun dossier de la chaîne ne contient de fichier.

A request for /blog/2024/hello is answered by the deepest error page GET /blog/2024/hello 404 src/routes/notfound.nexy scope / MATCHES src/routes/blog/notfound.nexy scope /blog MATCHES src/routes/blog/2024/notfound.nexy scope /blog/2024 ANSWERS Delete the last file and /blog answers. Delete that one and the built-in page answers.
Les portées d'une page d'erreur

Car /blog/2024/hello Nexy monte dans l'arbre : /blog/2024, puis /blog, puis /. Le premier dossier contenant un fichier répond. Un dossier correspond dans son intégralité : /blogger/hello n'est pas sous /blog, donc une copie dans blog/ n'y répond jamais.

Les quatre fichiers

Fichier Réponses Ce qui l'atteint
notfound.nexy 404 une URL à laquelle aucune route ne correspond, notFound()
errors.nexy 500 une exception rien n'est géré
forbidden.nexy 403 forbidden(), raise HTTPException(403)
unauthorized.nexy 401 unauthorized(), raise HTTPException(401)

loading.nexy reste réservé : il n'a pas encore d'effet d'exécution.

Un fichier quelque part dans src/routes/ suffit à Nexy pour répondre à ce statut : une copie à la racine répond à l'ensemble du projet, une copie dans un dossier répond à ce dossier et une URL en dehors de chaque copie obtient la page intégrée. Réservez une autre extension pour ces noms dans nexyconfig.py avec useNotFoundExtensions, useErrorsExtensions, useForbiddenExtensions et useUnauthorizedExtensions.

Votre première page de dossier

src/routes/blog/notfound.nexy
---title: Nothing here yet---<h1>That post is gone</h1><p>The <a href="/blog">blog</a> still has the others.</p>

Lancez le projet et demandez un post qui n'existe pas :

curl -i -H "Accept: text/html" http://localhost:3000/blog/old# HTTP/1.1 404 Not Found

Une URL en dehors du dossier conserve la page que vous aviez déjà :

curl -i -H "Accept: text/html" http://localhost:3000/about# HTTP/1.1 404 Not Found    (the root page, or the built-in one)

Une 401 qui mène quelque part

Le dossier d'une zone protégée répond 401 avec la page qui propose le chemin d'accès :

src/routes/private/unauthorized.nexy
---title: Sign in to continue---<h1>Sign in to see your notes</h1><a href="/sign-in" class="button">Sign in</a>
src/routes/private/dependencies.py
from nexy import unauthorizedfrom nexy.http import Request  def require_login(request: Request) -> None:    if not request.session.get("user"):        unauthorized(scheme="Bearer")  dependencies = [require_login]

Chaque appel et chaque statut garde ses deux réponses :

Qui demande 401 avec un fichier 401 sans un
Navigateur (Accept: text/html) la page du dossier la page intégrée
Client (Accept: application/json) {"detail": "..."} {"detail": "..."}

unauthorized(scheme="Bearer") ajoute WWW-Authenticate: Bearer aux deux réponses. Un détail construit à partir de la saisie de l'utilisateur est échappé en HTML dans la page.

Vérifiez-le

tests/test_private.py
from fastapi.testclient import TestClient from nexy.app import app  def test_a_private_url_asks_for_sign_in():    answer = TestClient(app).get("/private/notes")    assert answer.status_code == 401    assert "Sign in" in answer.text  def test_an_api_client_gets_json():    answer = TestClient(app).get(        "/private/notes", headers={"accept": "application/json"}    )    assert answer.json() == {"detail": "Unauthorized"}

Prochaines étapes

Modifier sur GitHub

Entrée ouvre le résultat, Échap ferme.