DocsUnidad 1: lo básico
Cree una aplicación de notas con Nexy, parte 3: rutas dinámicas y una API
La parte 3 le da a cada nota su propia URL, /notes/1, y muestra las mismas notas que JSON en /api/notes, ambas leídas desde un módulo Python.
Antes de comenzar: la aplicación de la parte 2.
Mantenga las notas en un módulo.
La página y la API leerán la misma lista. Muévelo a un módulo propio, con una función que encuentra una nota:
NOTES = {1: "Buy milk", 2: "Ship Nexy"} def find(note_id: int) -> str | None: return NOTES.get(note_id)Vincula cada nota a su página
from src.notes import NOTES notes = NOTES.items()<section class="app-page"> <h1>Notes</h1> <ul> {% for id, text in notes %} <li><a href="/notes/{{ id }}">{{ text }}</a></li> {% endfor %} </ul></section>from src.notes import NOTES notes = NOTES.items()<section class="app-page"> <h1>Notes</h1> <ul> {% for id, text in notes %} <li><a href="/notes/{{ id }}">{{ text }}</a></li> {% endfor %} </ul></section>Agregar una página por nota
Un nombre de carpeta o archivo entre paréntesis es un segmento de la URL: [id].nexy responde a /notes/1, /notes/2 y pasa el segmento a la página como accesorio. id: prop[int] lo convierte en un número, por lo que /notes/abc responde a 404 antes de que se ejecute la página.
from nexy import notFoundfrom src.notes import find id: prop[int]text = find(id)if text is None: notFound()<section class="app-page"> <h1>{{ text }}</h1> <a href="/notes">All notes</a></section>Un {id} en la ruta de un controlador es un segmento de la URL, pasado al método con ese nombre. id: int lo convierte en un número, por lo que /notes/abc responde a 404 antes de que se ejecute el método.
text: prop[str]<section class="app-page"> <h1>{{ text }}</h1> <a href="/notes">All notes</a></section>notFound() detiene la solicitud con un 404: una nota que no existe responde como una URL que no existe.
Servir las notas como JSON
Un archivo .py en src/routes/ es una ruta API. Cada función que lleva el nombre de un método HTTP responde a ese método:
from src.notes import NOTES async def GET(): return [{"id": id, "text": text} for id, text in NOTES.items()]Los tres controladores de los billetes, en un solo fichero. Cada método que lleva el nombre de un método HTTP responde a ese método:
from nexy import notFoundfrom nexy.decorators import Controllerfrom nexy.hooks import useViewsfrom src.notes import NOTES, find LAYOUT = "src/apps/layout.nexy" def page(view: str, **context: object): return useViews(LAYOUT, context={"children": useViews(view, context=context)}) @Controller("/notes")class NotesController: async def get(self): return page("src/apps/notes/notes_view.nexy") @Controller("/notes/{id}")class NoteController: async def get(self, id: int): text = find(id) if text is None: notFound() return page("src/apps/notes/note_view.nexy", text=text) @Controller("/api/notes")class NotesApiController: async def get(self) -> list[dict]: return [{"id": id, "text": text} for id, text in NOTES.items()]from nexy.decorators import Module from .app_controller import AboutController, AppControllerfrom .notes.notes_controller import NoteController, NotesApiController, NotesController @Module()class AppModule: controllers = [AppController, AboutController, NotesController, NoteController, NotesApiController]Verifique las tres URL:
- http://localhost:3000/notes/1 muestra Comprar leche;
- http://localhost:3000/notes/9 responde Página no encontrada;
curl http://localhost:3000/api/notesimprime[{"id":1,"text":"Buy milk"},{"id":2,"text":"Ship Nexy"}].
La API aparece, con su esquema, en http://localhost:3000/docs.
lo que aprendiste
[id].nexyes un segmento dinámico;id: prop[int]lo lee y lo convierte.- Un archivo
.pyensrc/routes/responde JSON, una función por método HTTP.
{id}en la ruta de un controlador es un segmento dinámico;id: intlo convierte.- Un método de controlador que devuelve datos responde JSON; uno que devuelve
useViewsresponde una página.
notFound()responde404desde cualquier lugar; un módulo compartido mantiene las páginas y la API en sintonía.
Próximos pasos
- Parte 4: componentes
- Excepciones y errores:
notFound,redirecty las demás salidas