Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Playground/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
using GenHTTP.Engine.Internal;

using GenHTTP.Modules.IO;
using GenHTTP.Modules.Practices;

var app = Content.From(Resource.FromString("Hello World!"));
using GenHTTP.Playground.Samples;

await Host.Create()
.Handler(app)
.RunAsync();
var sample = CustomFrameworkSample.Create();

return await Host.Create()
.Handler(sample)
.Development()
.Defaults()
.RunAsync();
14 changes: 14 additions & 0 deletions Playground/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# GenHTTP Playground

The playground provides code samples for quick reference and allows developers to
quickly validate things.

| Sample | Description |
|----------------------------------------------------------------------|----------------------------------------------------------------------------------|
| [Layouting](./Samples/LayoutingSample.cs) | Allows an app to use multiple handlers by adding routing. |
| [Webservices](./Samples/WebserviceSample.cs) | Implements a REST webservice via a handler class. |
| [Functional](./Samples/FunctionalSample.cs) | Uses delegates to implement a web service (similar to ASP.NET Core Minimal API). |
| [Controllers](./Samples/ControllerSample.cs) | Uses controllers to implement a web service (similar to ASP.NET Core MVC). |
| [Static Files](./Samples/StaticFileSample.cs) | Serves static files from a directory. |
| [Static Websites](./Samples/StaticWebsiteSample.cs) | Hosts a static website (with `index.html` support). |
| [Single Page Applications](./Samples/SinglePageApplicationSample.cs) | Hosts a SPA such as a React or Angular application. |
62 changes: 62 additions & 0 deletions Playground/Samples/ControllerSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.Controllers;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.Reflection;

namespace GenHTTP.Playground.Samples;

public static class ControllerSample
{

public static IHandlerBuilder Create()
{
/*
*
* Shows how to declare and register a controller that will be invoked
* to handle incoming HTTP requests.
*
* See https://genhttp.org/documentation/content/frameworks/controllers/
*
*/

return Layout.Create()
.AddController<BookController>("books");
}

public record Book(int Id, string Title);

public class BookController
{
private static readonly List<Book> Books =
[
new(1, "Lord of the Rings")
];

// GET http://localhost:8080/books/
[ControllerAction]
public List<Book> Index() => Books;

// PUT http://localhost:8080/books/create with JSON/XML/... payload
[ControllerAction(Method.Put)]
public Book Create(Book book)
{
var toAdd = book with
{
Id = Books.Max(b => b.Id) + 1
};

Books.Add(toAdd);
return toAdd;
}

// DELETE http://localhost:8080/books/delete/1
[ControllerAction(Method.Delete)]
public void Delete([FromPath] int id)
{
Books.RemoveAll(b => b.Id == id);
}

}

}
81 changes: 81 additions & 0 deletions Playground/Samples/CustomFrameworkSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using GenHTTP.Api.Content;
using GenHTTP.Api.Infrastructure;
using GenHTTP.Api.Protocol;

using GenHTTP.Modules.ApiBrowsing;
using GenHTTP.Modules.Conversion;
using GenHTTP.Modules.Functional.Provider;
using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.OpenApi;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Reflection.Operations;

namespace GenHTTP.Playground.Samples;

public static class CustomFrameworkSample
{

public static IHandlerBuilder Create()
{
/*
*
* Shows how to implement a custom framework.
*
* See https://genhttp.org/documentation/content/frameworks/custom/
*
*/

return Layout.Create()
.Add(new CustomFrameworkHandler())
.AddOpenApi()
.AddScalar();
}

public class CustomFrameworkHandler : IHandler, IServiceMethodProvider
{
private MethodCollection? _methods;

public MethodCollection Methods => _methods ?? throw new InvalidOperationException("Handler is not prepared yet");

public async ValueTask PrepareAsync(IServer server)
{
var list = new List<MethodHandler>();

// specify the supported methods of the operation we are exposing
var supportedMethods = new MethodConfiguration([RequestMethod.Get]);

// the actual piece of code to be executed - either a method info or a delegate
var methodInfo = GetType().GetMethod("ExposedMethod")!;

// auto enables code generation, otherwise reflection only
var executionSettings = new ExecutionSettings(ExecutionMode.Auto);

// configures the behavior for serialization, injection and formatting
var registry = new MethodRegistry(
Serialization.Default().Build(),
Injection.Default().Build(),
Formatting.Default().Build()
);

// build the operation we would like to provide
var operation = OperationBuilder.Create(server, ":id", methodInfo, null, executionSettings, supportedMethods, registry);

// create a method handler from the operation which will serve it as an HTTP endpoint
// this handler requires an instance provider which tells the framework on which
// object to invoke the given method info or delegate
list.Add(new MethodHandler(operation, (_) => new(this), registry));

// build a method collection handler from all collected operations
// this handler is responsible for routing
_methods = new MethodCollection(list);

await _methods.PrepareAsync(server);
}

public ValueTask<IResponse?> HandleAsync(IRequest request) => Methods.HandleAsync(request);

public string ExposedMethod(int id) => id.ToString();

}

}
47 changes: 47 additions & 0 deletions Playground/Samples/FunctionalSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.Functional;
using GenHTTP.Modules.Layouting;

namespace GenHTTP.Playground.Samples;

public static class FunctionalSample
{

public static IHandlerBuilder Create()
{
/*
*
* Shows how to use delegates that will be invoked
* to handle incoming HTTP requests.
*
* See https://genhttp.org/documentation/content/frameworks/functional/
*
*/

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

var service = Inline.Create()
.Get(() => books) // GET http://localhost:8080/books/
.Put((Book book) => // PUT http://localhost:8080/books/ with JSON/XML/... payload
{
var toAdd = book with
{
Id = books.Max(b => b.Id) + 1
};

books.Add(toAdd);
return toAdd;
})
.Delete(":id", (int id) => books.RemoveAll(b => b.Id == id)); // DELETE http://localhost:8080/books/1

return Layout.Create()
.Add("books", service);
}

public record Book(int Id, string Title);

}
38 changes: 38 additions & 0 deletions Playground/Samples/LayoutingSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.Files;
using GenHTTP.Modules.Functional;
using GenHTTP.Modules.Layouting;

namespace GenHTTP.Playground.Samples;

public static class LayoutingSample
{

public static IHandlerBuilder Create()
{
/*
*
* Layouts allow you to structure your web application and divide it into
* different logical parts. The layout will route incoming requests to the designated
* handler. Layouts can be nested as needed.
*
* See https://genhttp.org/documentation/content/handlers/layouting/
*
*/

// serve static files from the current directory
var assets = Assets.From("./");

// define a simple REST API
var api = Inline.Create()
.Get(() => "Hello World!");

// assemble our application from the parts above and
// register them at the given URLs
return Layout.Create()
.Add("assets", assets) // e.g. GET http://localhost:8080/assets/GenHTTP.Playground.xml
.Add("api", api); // e.g. GET http://localhost:8080/api/
}

}
27 changes: 27 additions & 0 deletions Playground/Samples/SinglePageApplicationSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.IO;
using GenHTTP.Modules.SinglePageApplications;

namespace GenHTTP.Playground.Samples;

public static class SinglePageApplicationSample
{

public static IHandlerBuilder Create()
{
/*
*
* Serves a single page application (SPA) from a directory (or resource tree in general).
*
* See https://genhttp.org/documentation/content/frameworks/single-page-applications/
*
*/

var files = ResourceTree.FromDirectory("/var/app");

return SinglePageApplication.From(files);
}

}

24 changes: 24 additions & 0 deletions Playground/Samples/StaticFileSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.Files;

namespace GenHTTP.Playground.Samples;

public static class StaticFileSample
{

public static IHandlerBuilder Create()
{
/*
*
* Serves files from a given directory or resource tree.
*
* See https://genhttp.org/documentation/content/handlers/static-content/
*
*/

// e.g. GET http://localhost:8080/assets/GenHTTP.Playground.xml
return Assets.From("./");
}

}
27 changes: 27 additions & 0 deletions Playground/Samples/StaticWebsiteSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.IO;
using GenHTTP.Modules.StaticWebsites;

namespace GenHTTP.Playground.Samples;

public static class StaticWebsiteSample
{

public static IHandlerBuilder Create()
{
/*
*
* Serves a static website from a directory (or resource tree in general).
*
* See https://genhttp.org/documentation/content/frameworks/static-websites/
*
*/

var files = ResourceTree.FromDirectory("/var/www");

return StaticWebsite.From(files);
}

}

Loading
Loading