Pages

Live on this server

Renders HTML pages from templates on the server.

Renders HTML pages on the server, for example for an internal tool that does not need a frontend framework. The list of books is rendered from a Cottle template with the books as its model; the about page uses the look of the pages GenHTTP renders itself, such as its error pages.

Templates do not escape HTML for you, so the titles pass Escaped() first. In an application, the template would rather be a file or an embedded resource than a string.

To run it, create a console app (dotnet new console), add GenHTTP (dotnet add package GenHTTP.Full), replace Program.cs with the code below and start it with dotnet run - it answers at http://localhost:8080/.

Program.cs68 lines
using Cottle;

using GenHTTP.Engine.Internal;

using GenHTTP.Api.Protocol;

using GenHTTP.Modules.Functional;
using GenHTTP.Modules.IO;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.Pages;
using GenHTTP.Modules.Practices;

var books = new List<Book> { new(1, "Lord of the Rings"), new(2, "Pride & Prejudice") };

var template = Renderer.From(Resource.FromString(BooksPage.Template).Build());

var bookList = Inline.Create()
                     .Get(async (IRequest request) =>
                     {
                         var model = new Dictionary<Value, Value>
                         {
                             ["books"] = Value.FromEnumerable(books.Select(b => Value.FromDictionary(new Dictionary<Value, Value>
                             {
                                 ["id"] = b.Id,
                                 ["title"] = b.Title.Escaped() // the template engine does not escape HTML for you
                             })))
                         };

                         return request.GetPage(await template.RenderAsync(model));
                     });

var about = Inline.Create()
                  .Get(async (IRequest request) => request.GetPage(await Renderer.Server.RenderAsync("About", "<p>This library runs on GenHTTP.</p>")));

var app = Layout.Create()
                .Add("books", bookList) // GET /books/ (rendered from a Cottle template)
                .Add("about", about); // GET /about/ (in the style of the server's own pages)

await Host.Create()
          .Handler(app)
          .Defaults()
          .RunAsync();

public record Book(int Id, string Title);

public static class BooksPage
{

    public const string Template =
        """
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Books</title>
        </head>
        <body>
            <table>
                <tr><th>ID</th><th>Title</th></tr>
                {for book in books:
                <tr><td>{book.id}</td><td>{book.title}</td></tr>
                }
            </table>
        </body>
        </html>
        """;

}

Try it

Send the requests to the sample running on this server - change the path, headers or body as you like, or copy them as curl commands.

  1. Page rendered from a template

    PAGE /demo/pages/books/ Open
  2. Page in the style of the server

    PAGE /demo/pages/about/ Open