dicej / spin-dotnet-sdk

Experimental Spin SDK for .NET
1 stars 4 forks source link

[samples/http-aspnetcore] POST parameter binding is not working #18

Closed bacongobbler closed 2 months ago

bacongobbler commented 2 months ago

Modifying the sample to add a few endpoints like the following:

using System.Text;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Spin.Http;
using SpinHttpWorld.wit.imports.wasi.http.v0_2_0;

namespace SpinHttpWorld.wit.exports.wasi.http.v0_2_0;

public class IncomingHandlerImpl : IIncomingHandler
{
    /// <summary>Handle the specified incoming HTTP request and send a response
    /// via `responseOut`.</summary>
    public static void Handle(ITypes.IncomingRequest request, ITypes.ResponseOutparam responseOut)
    {
        var builder = WebApplication.CreateSlimBuilder(new string[0]);
        builder.Services.ConfigureHttpJsonOptions(options =>
        {
            options.SerializerOptions.TypeInfoResolverChain.Insert(
                0,
                AppJsonSerializerContext.Default
            );
        });
        builder.Services.AddSingleton<IServer, WasiHttpServer>();
        builder.Logging.ClearProviders();
        builder
            .Logging.AddProvider(new WasiLoggingProvider())
            .AddFilter("Microsoft.AspNetCore.DataProtection", LogLevel.Error);

        var app = builder.Build();
        app.UseStaticFiles();

        app.MapGet("/", () => "Hello, world! See also: /weatherforecast and /mystaticpage.html");

        app.MapGet(
            "/weatherforecast",
            () =>
            {
                var summaries = new[]
                {
                    "Freezing",
                    "Bracing",
                    "Chilly",
                    "Cool",
                    "Mild",
                    "Warm",
                    "Balmy",
                    "Hot",
                    "Sweltering",
                    "Scorching"
                };
                var forecast = Enumerable
                    .Range(1, 5)
                    .Select(index => new Forecast()
                    {
                        Date = DateTime.Now.AddDays(index),
                        TempC = Random.Shared.Next(-20, 55),
                        Summary = summaries[Random.Shared.Next(summaries.Length)]
                    })
                    .ToArray();
                return forecast;
            }
        );

        app.MapPost("/post", () =>
        {
            return "Hello world!";
        });

        app.MapPost("/data", (Message msg) =>
        {
            return msg.Greeting;
        });

        Func<Task> task = async () =>
        {
            await app.StartAsync();
            await WasiHttpServer.HandleRequestAsync(request, responseOut);
        };
        RequestHandler.Run(task());
    }
}

public record Message(string Greeting);

public class Forecast
{
    public DateTime Date { get; set; }
    public int TempC { get; set; }
    public string Summary { get; set; }
}

[JsonSerializable(typeof(Message[]))]
[JsonSerializable(typeof(Forecast[]))]
internal partial class AppJsonSerializerContext : JsonSerializerContext { }

POST requests without parameter binding works:

><> curl -XPOST localhost:3000/post
Hello world!

But an endpoint with a bound input parameter returns a 400 Bad Request.

><> curl -XPOST localhost:3000/data -H "Content-Type: application/json" -d '{"greeting":"warm"}' -i
HTTP/1.1 400 Bad Request
transfer-encoding: chunked
date: Wed, 21 Aug 2024 18:57:13 GMT

@dicej pointed out that this may be due to a bug in WasiHttpServer.cs.