Webservices

Live on this server

Implements a REST webservice via a handler class.

A small API for a book shelf: clients list the books, add one and delete one. The API is a plain C# class whose methods are marked with [ResourceMethod] - the attribute sets the HTTP method and path, and GenHTTP reads the parameters from the request and writes the return value as the response.

AddService<BookService>("books") serves the class below /books/. Books are read and written as JSON, or in another format such as XML if the client asks for it. Throwing a ProviderException ends a request with the given status, here 409 when the shelf is full.

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.cs58 lines
using GenHTTP.Engine.Internal;

using GenHTTP.Api.Content;
using GenHTTP.Api.Protocol;

using GenHTTP.Modules.Layouting;
using GenHTTP.Modules.Practices;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Webservices;

var app = Layout.Create()
                .AddService<BookService>("books");

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

public record Book(int Id, string Title);

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

    // GET /books/
    [ResourceMethod]
    public List<Book> List()
    {
        lock (Books) return [..Books];
    }

    // PUT /books/ with a book as JSON, XML, ...
    [ResourceMethod(Method.Put)]
    public Book Add(Book book)
    {
        lock (Books)
        {
            if (Books.Count >= 50)
            {
                throw new ProviderException(ResponseStatus.Conflict, "The shelf is full, please delete a book first");
            }

            var added = book with { Id = Books.Select(b => b.Id).DefaultIfEmpty().Max() + 1 };

            Books.Add(added);

            return added;
        }
    }

    // DELETE /books/1
    [ResourceMethod(Method.Delete, ":id")]
    public void Delete(int id)
    {
        lock (Books) Books.RemoveAll(b => b.Id == id);
    }

}

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. List all books

    GET
    curl -i 'https://genhttp.org/demo/webservices/books/'
  2. Add a book

    PUT
    Headers and body
    curl -i -X PUT -H 'Content-Type: application/json' -d '{ "title": "The Hobbit" }' 'https://genhttp.org/demo/webservices/books/'
  3. Delete a book

    DELETE
    Headers and body
    curl -i -X DELETE 'https://genhttp.org/demo/webservices/books/1'