Skip to content

Commit

Permalink
First API draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaliumhexacyanoferrat committed Jan 3, 2024
1 parent 6738b6d commit 2c08aa2
Show file tree
Hide file tree
Showing 10 changed files with 280 additions and 67 deletions.
15 changes: 15 additions & 0 deletions API/Content/Services/IResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using GenHTTP.Api.Protocol;

namespace GenHTTP.Api.Content.Services
{

public interface IResult
{

object? Payload { get; }

void Apply(IResponseBuilder builder);

}

}
154 changes: 154 additions & 0 deletions API/Content/Services/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;

using GenHTTP.Api.Protocol;

namespace GenHTTP.Api.Content.Services
{

public class Result<T> : IResult, IResponseModification<Result<T>>
{
private FlexibleResponseStatus? _Status;

private Dictionary<string, string>? _Headers;

private DateTime? _Expires;

private DateTime? _Modified;

private List<Cookie>? _Cookies;

private FlexibleContentType? _ContentType;

private string? _Encoding;

#region Get-/Setters

public T? Payload { get; }

object? IResult.Payload => Payload;

#endregion

#region Initialization

public Result(T? payload)
{
Payload = payload;
}

#endregion

#region Functionality

public Result<T> Status(ResponseStatus status)
{
_Status = new(status);
return this;
}

public Result<T> Status(int status, string reason)
{
_Status = new FlexibleResponseStatus(status, reason);
return this;
}

public Result<T> Header(string key, string value)
{
if (_Headers == null)
{
_Headers = new();
}

_Headers[key] = value;

return this;
}

public Result<T> Expires(DateTime expiryDate)
{
_Expires = expiryDate;
return this;
}

public Result<T> Modified(DateTime modificationDate)
{
_Modified = modificationDate;
return this;
}

public Result<T> Cookie(Cookie cookie)
{
if (_Cookies == null)
{
_Cookies = new();
}

_Cookies.Add(cookie);

return this;
}

public Result<T> Type(FlexibleContentType contentType)
{
_ContentType = contentType;
return this;
}

public Result<T> Encoding(string encoding)
{
_Encoding = encoding;
return this;
}

public void Apply(IResponseBuilder builder)
{
if (_Status != null)
{
var value = _Status.Value;

builder.Status(value.RawStatus, value.Phrase);
}

if (_Headers != null)
{
foreach (var kv in _Headers)
{
builder.Header(kv.Key, kv.Value);
}
}

if (_Expires != null)
{
builder.Expires(_Expires.Value);
}

if (_Modified != null)
{
builder.Modified(_Modified.Value);
}

if (_Cookies != null)
{
foreach (var cookie in _Cookies)
{
builder.Cookie(cookie);
}
}

if (_ContentType is not null)
{
builder.Type(_ContentType);
}

if (_Encoding != null)
{
builder.Encoding(_Encoding);
}
}

#endregion

}

}
58 changes: 2 additions & 56 deletions API/Protocol/IResponseBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,85 +1,31 @@
using System;

using GenHTTP.Api.Infrastructure;
using GenHTTP.Api.Infrastructure;

namespace GenHTTP.Api.Protocol
{

/// <summary>
/// Allows to configure a HTTP response to be send.
/// </summary>
public interface IResponseBuilder : IBuilder<IResponse>
public interface IResponseBuilder : IBuilder<IResponse>, IResponseModification<IResponseBuilder>
{

/// <summary>
/// The request the response belongs to.
/// </summary>
IRequest Request { get; }

/// <summary>
/// Specifies the HTTP status code of the response.
/// </summary>
/// <param name="status">The HTTP status code of the response</param>
IResponseBuilder Status(ResponseStatus status);

/// <summary>
/// Specifies the HTTP status code of the response.
/// </summary>
/// <param name="status">The status code of the response</param>
/// <param name="reason">The reason phrase of the response (such as "Not Found" for 404)</param>
IResponseBuilder Status(int status, string reason);

/// <summary>
/// Sets the given header field on the response. Changing HTTP
/// protocol headers may cause incorrect behavior.
/// </summary>
/// <param name="key">The name of the header to be set</param>
/// <param name="value">The value of the header field</param>
IResponseBuilder Header(string key, string value);

/// <summary>
/// Sets the expiration date of the response.
/// </summary>
/// <param name="expiryDate">The expiration date of the response</param>
IResponseBuilder Expires(DateTime expiryDate);

/// <summary>
/// Sets the point in time when the requested resource has been
/// modified last.
/// </summary>
/// <param name="modificationDate">The point in time when the requested resource has been modified last</param>
IResponseBuilder Modified(DateTime modificationDate);

/// <summary>
/// Adds the given cookie to the response.
/// </summary>
/// <param name="cookie">The cookie to be added</param>
IResponseBuilder Cookie(Cookie cookie);

/// <summary>
/// Specifies the content to be sent to the client.
/// </summary>
/// <param name="content">The content to be send to the client</param>
IResponseBuilder Content(IResponseContent content);

/// <summary>
/// Specifies the content type of this response.
/// </summary>
/// <param name="contentType">The content type of this response</param>
IResponseBuilder Type(FlexibleContentType contentType);

/// <summary>
/// Specifies the length of the content stream, if known.
/// </summary>
/// <param name="length">The length of the content stream</param>
IResponseBuilder Length(ulong length);

/// <summary>
/// Sets the encoding of the content.
/// </summary>
/// <param name="encoding">The encoding of the content</param>
IResponseBuilder Encoding(string encoding);

}

}
63 changes: 63 additions & 0 deletions API/Protocol/IResponseModification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;

namespace GenHTTP.Api.Protocol
{

public interface IResponseModification<T>

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)

Check warning on line 6 in API/Protocol/IResponseModification.cs

View workflow job for this annotation

GitHub Actions / build

Add the 'out' keyword to parameter 'T' to make it 'covariant'. (https://rules.sonarsource.com/csharp/RSPEC-3246)
{

/// <summary>
/// Specifies the HTTP status code of the response.
/// </summary>
/// <param name="status">The HTTP status code of the response</param>
T Status(ResponseStatus status);

/// <summary>
/// Specifies the HTTP status code of the response.
/// </summary>
/// <param name="status">The status code of the response</param>
/// <param name="reason">The reason phrase of the response (such as "Not Found" for 404)</param>
T Status(int status, string reason);

/// <summary>
/// Sets the given header field on the response. Changing HTTP
/// protocol headers may cause incorrect behavior.
/// </summary>
/// <param name="key">The name of the header to be set</param>
/// <param name="value">The value of the header field</param>
T Header(string key, string value);

/// <summary>
/// Sets the expiration date of the response.
/// </summary>
/// <param name="expiryDate">The expiration date of the response</param>
T Expires(DateTime expiryDate);

/// <summary>
/// Sets the point in time when the requested resource has been
/// modified last.
/// </summary>
/// <param name="modificationDate">The point in time when the requested resource has been modified last</param>
T Modified(DateTime modificationDate);

/// <summary>
/// Adds the given cookie to the response.
/// </summary>
/// <param name="cookie">The cookie to be added</param>
T Cookie(Cookie cookie);

/// <summary>
/// Specifies the content type of this response.
/// </summary>
/// <param name="contentType">The content type of this response</param>
T Type(FlexibleContentType contentType);

/// <summary>
/// Sets the encoding of the content.
/// </summary>
/// <param name="encoding">The encoding of the content</param>
T Encoding(string encoding);

}

}
2 changes: 1 addition & 1 deletion Modules/Controllers/Provider/ControllerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private IEnumerable<Func<IHandler, MethodHandler>> AnalyzeMethods(Type type, Ser

var path = DeterminePath(method, arguments);

yield return (parent) => new MethodHandler(parent, method, path, () => new T(), annotation, ResponseProvider.GetResponse, formats, injection);
yield return (parent) => new MethodHandler(parent, method, path, () => new T(), annotation, ResponseProvider.GetResponseAsync, formats, injection);
}
}

Expand Down
2 changes: 1 addition & 1 deletion Modules/Functional/Provider/InlineHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private IEnumerable<Func<IHandler, MethodHandler>> AnalyzeMethods(List<InlineFun

var target = function.Delegate.Target ?? throw new InvalidOperationException("Delegate target must not be null");

yield return (parent) => new MethodHandler(parent, function.Delegate.Method, path, () => target, function.Configuration, ResponseProvider.GetResponse, formats, injection);
yield return (parent) => new MethodHandler(parent, function.Delegate.Method, path, () => target, function.Configuration, ResponseProvider.GetResponseAsync, formats, injection);
}
}

Expand Down
23 changes: 23 additions & 0 deletions Modules/Reflection/Adjustments.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;

using GenHTTP.Api.Protocol;

namespace GenHTTP.Modules.Reflection
{

internal static class Adjustments
{

internal static IResponseBuilder Adjust(this IResponseBuilder builder, Action<IResponseBuilder>? adjustments)
{
if (adjustments != null)
{
adjustments(builder);
}

return builder;
}

}

}
6 changes: 3 additions & 3 deletions Modules/Reflection/MethodHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public sealed class MethodHandler : IHandler

private Func<object> InstanceProvider { get; }

private Func<IRequest, IHandler, object?, ValueTask<IResponse?>> ResponseProvider { get; }
private Func<IRequest, IHandler, object?, Action<IResponseBuilder>?, ValueTask<IResponse?>> ResponseProvider { get; }

private SerializationRegistry Serialization { get; }

Expand All @@ -60,7 +60,7 @@ public sealed class MethodHandler : IHandler
#region Initialization

public MethodHandler(IHandler parent, MethodInfo method, MethodRouting routing, Func<object> instanceProvider, IMethodConfiguration metaData,
Func<IRequest, IHandler, object?, ValueTask<IResponse?>> responseProvider, SerializationRegistry serialization, InjectionRegistry injection)
Func<IRequest, IHandler, object?, Action<IResponseBuilder>?, ValueTask<IResponse?>> responseProvider, SerializationRegistry serialization, InjectionRegistry injection)
{
Parent = parent;

Expand Down Expand Up @@ -88,7 +88,7 @@ public MethodHandler(IHandler parent, MethodInfo method, MethodRouting routing,

var result = Invoke(arguments);

return await ResponseProvider(request, this, await UnwrapAsync(result));
return await ResponseProvider(request, this, await UnwrapAsync(result), null);
}

private async ValueTask<object?[]> GetArguments(IRequest request)
Expand Down
Loading

0 comments on commit 2c08aa2

Please sign in to comment.