Skip to content

Make http status code available #1504

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 5, 2023
Merged
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
15 changes: 11 additions & 4 deletions Libraries/src/Amazon.Lambda.Annotations/APIGateway/HttpResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public enum ProtocolVersion {
/// </example>
public interface IHttpResult
{
/// <summary>
/// The Status code of the HttpResult
/// </summary>
HttpStatusCode StatusCode { get; }

/// <summary>
/// Used by the Lambda Annotations framework to serialize the IHttpResult to the correct JSON response.
/// </summary>
Expand Down Expand Up @@ -126,15 +131,14 @@ public class HttpResults : IHttpResult
private const string CONTENT_TYPE_TEXT_PLAIN = "text/plain";
private const string CONTENT_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream";

private HttpStatusCode _statusCode;
private string _body;
private IDictionary<string, IList<string>> _headers;
private bool _isBase64Encoded;
private string _defaultContentType;

private HttpResults(HttpStatusCode statusCode, object body = null)
{
_statusCode = statusCode;
StatusCode = statusCode;

FormatBody(body);
}
Expand Down Expand Up @@ -387,6 +391,9 @@ private void FormatBody(object body)
#endif
}

/// <inheritdoc/>
public HttpStatusCode StatusCode { get; }

/// <summary>
/// Serialize the IHttpResult into the expect format for the event source.
/// </summary>
Expand All @@ -410,7 +417,7 @@ public Stream Serialize(HttpResultSerializationOptions options)
{
var response = new APIGatewayV1Response
{
StatusCode = (int)_statusCode,
StatusCode = (int)StatusCode,
Body = _body,
MultiValueHeaders = _headers,
IsBase64Encoded = _isBase64Encoded
Expand All @@ -422,7 +429,7 @@ public Stream Serialize(HttpResultSerializationOptions options)
{
var response = new APIGatewayV2Response
{
StatusCode = (int)_statusCode,
StatusCode = (int)StatusCode,
Body = _body,
Headers = ConvertToV2MultiValueHeaders(_headers),
IsBase64Encoded = _isBase64Encoded
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Amazon.Lambda.Annotations.APIGateway;
using Xunit;
using System.IO;
using System.Text.Json.Nodes;
using System.Linq;

namespace Amazon.Lambda.Annotations.SourceGenerators.Tests
Expand All @@ -16,6 +15,9 @@ public class HttpResultsTest
public void OkNoBody()
{
var result = HttpResults.Ok();

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK);
}

Expand All @@ -24,6 +26,9 @@ public void OkStringBody()
{
var body = "Hello World";
var result = HttpResults.Ok(body);

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, body, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "text/plain" } }
Expand All @@ -36,6 +41,9 @@ public void OverrideContentType()
{
var body = "Hello World";
var result = HttpResults.Ok(body).AddHeader("content-type", "custom/foo");

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, body, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "custom/foo" } }
Expand All @@ -49,6 +57,9 @@ public void OkByteArrayBody()
var body = new byte[] { 0x01, 0x02 };

var result = HttpResults.Ok(body);

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, Convert.ToBase64String(body), isBase64Encoded: true, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "application/octet-stream" } }
Expand All @@ -61,6 +72,9 @@ public void OkStreamBody()
{
var body = new byte[] { 0x01, 0x02 };
var result = HttpResults.Ok(new MemoryStream(body));

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, Convert.ToBase64String(body), isBase64Encoded: true, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "application/octet-stream" } }
Expand All @@ -73,6 +87,9 @@ public void OkListOfBytesBody()
{
var body = new byte[] { 0x01, 0x02 };
var result = HttpResults.Ok(new List<byte>(body));

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, Convert.ToBase64String(body), isBase64Encoded: true, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "application/octet-stream" } }
Expand All @@ -85,6 +102,9 @@ public void OkWithTypeBody()
{
var body = new FakeBody();
var result = HttpResults.Ok(body);

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, "{\"Id\":1}", isBase64Encoded: false, headers: new Dictionary<string, IList<string>>
{
{ "content-type", new List<string> { "application/json" } }
Expand All @@ -99,6 +119,8 @@ public void OkWithSingleValueHeader()
.AddHeader("header1", "value1")
.AddHeader("header2", "value2");

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -117,6 +139,8 @@ public void OkWithMultiValueHeader()
.AddHeader("header2", "bar1")
.AddHeader("header2", "bar2");

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -130,34 +154,49 @@ public void OkWithMultiValueHeader()
public void Accepted()
{
var result = HttpResults.Accepted();

Assert.Equal(HttpStatusCode.Accepted, result.StatusCode);

ValidateResult(result, HttpStatusCode.Accepted);
}

[Fact]
public void BadRequest()
{
var result = HttpResults.BadRequest();

Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode);

ValidateResult(result, HttpStatusCode.BadRequest);
}

[Fact]
public void Conflict()
{
var result = HttpResults.Conflict();

Assert.Equal(HttpStatusCode.Conflict, result.StatusCode);

ValidateResult(result, HttpStatusCode.Conflict);
}

[Fact]
public void Created()
{
var result = HttpResults.Created();

Assert.Equal(HttpStatusCode.Created, result.StatusCode);

ValidateResult(result, HttpStatusCode.Created);
}

[Fact]
public void CreatedWithUriAndBody()
{
var result = HttpResults.Created("http://localhost/foo", "Resource Created");

Assert.Equal(HttpStatusCode.Created, result.StatusCode);

ValidateResult(result, HttpStatusCode.Created, "Resource Created",
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -171,13 +210,19 @@ public void CreatedWithUriAndBody()
public void Forbid()
{
var result = HttpResults.Forbid();

Assert.Equal(HttpStatusCode.Forbidden, result.StatusCode);

ValidateResult(result, HttpStatusCode.Forbidden);
}

[Fact]
public void Redirect_PermanentRedirect()
{
var result = HttpResults.Redirect("http://localhost/foo", permanent: true, preserveMethod: true);

Assert.Equal(HttpStatusCode.PermanentRedirect, result.StatusCode);

ValidateResult(result, HttpStatusCode.PermanentRedirect,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -190,6 +235,9 @@ public void Redirect_PermanentRedirect()
public void Redirect_MovedPermanently()
{
var result = HttpResults.Redirect("http://localhost/foo", permanent: true, preserveMethod: false);

Assert.Equal(HttpStatusCode.MovedPermanently, result.StatusCode);

ValidateResult(result, HttpStatusCode.MovedPermanently,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -202,6 +250,9 @@ public void Redirect_MovedPermanently()
public void Redirect_TemporaryRedirect()
{
var result = HttpResults.Redirect("http://localhost/foo", permanent: false, preserveMethod: true);

Assert.Equal(HttpStatusCode.TemporaryRedirect, result.StatusCode);

ValidateResult(result, HttpStatusCode.TemporaryRedirect,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -214,6 +265,9 @@ public void Redirect_TemporaryRedirect()
public void Redirect_Redirect()
{
var result = HttpResults.Redirect("http://localhost/foo", permanent: false, preserveMethod: false);

Assert.Equal(HttpStatusCode.Redirect, result.StatusCode);

ValidateResult(result, HttpStatusCode.Redirect,
headers: new Dictionary<string, IList<string>>
{
Expand All @@ -226,13 +280,19 @@ public void Redirect_Redirect()
public void NotFound()
{
var result = HttpResults.NotFound();

Assert.Equal(HttpStatusCode.NotFound, result.StatusCode);

ValidateResult(result, HttpStatusCode.NotFound);
}

[Fact]
public void Unauthorized()
{
var result = HttpResults.Unauthorized();

Assert.Equal(HttpStatusCode.Unauthorized, result.StatusCode);

ValidateResult(result, HttpStatusCode.Unauthorized);
}

Expand All @@ -244,6 +304,8 @@ public void MixCaseHeaders()
.AddHeader("key", "value2")
.AddHeader("KEY", "VALUE3");

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

ValidateResult(result, HttpStatusCode.OK, headers: new Dictionary<string, IList<string>>
{
{"key", new List<string> {"value1", "value2", "VALUE3"} }
Expand All @@ -254,13 +316,19 @@ public void MixCaseHeaders()
public void InternalServerError()
{
var result = HttpResults.InternalServerError();

Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode);

ValidateResult(result, HttpStatusCode.InternalServerError);
}

[Fact]
public void BadGateway()
{
var result = HttpResults.BadGateway();

Assert.Equal(HttpStatusCode.BadGateway, result.StatusCode);

ValidateResult(result, HttpStatusCode.BadGateway);
}

Expand All @@ -270,13 +338,19 @@ public void BadGateway()
public void ServiceUnavailable_WithoutRetryAfter(int? delay)
{
var result = HttpResults.ServiceUnavailable(delay);

Assert.Equal(HttpStatusCode.ServiceUnavailable, result.StatusCode);

ValidateResult(result, HttpStatusCode.ServiceUnavailable);
}

[Fact]
public void ServiceUnavailable_WithRetryAfter()
{
var result = HttpResults.ServiceUnavailable(100);

Assert.Equal(HttpStatusCode.ServiceUnavailable, result.StatusCode);

ValidateResult(result, HttpStatusCode.ServiceUnavailable, headers: new Dictionary<string, IList<string>>
{
{"retry-after", new List<string> {"100"} }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Net;
using Amazon.Lambda.Annotations.APIGateway;
using Amazon.Lambda.Core;
using Xunit;

namespace Amazon.Lambda.Annotations.SourceGenerators.Tests
{
public class HtttpResultsStatusCodeUsage
{
[Fact]
public void UsageOfIHttpResultStatusCode()
{
var sut = new Functions();

var result = sut.GetResponse("good", null);

Assert.Equal(HttpStatusCode.OK, result.StatusCode);

result = sut.GetResponse("not good", null);

Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode);
}
}

public class Functions
{
[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/resource/{type}")]
public IHttpResult GetResponse(string type, ILambdaContext context)
{
return type == "good" ?
HttpResults.Ok() :
HttpResults.BadRequest();
}
}
}