using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
using Amazon;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Newtonsoft.Json;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace BlueprintBaseName._1
{
public class Functions
{
// This const is the name of the environment variable that the serverless.template will use to set
// the name of the DynamoDB table used to store blog posts.
const string TABLENAME_ENVIRONMENT_VARIABLE_LOOKUP = "BlogTable";
public const string ID_QUERY_STRING_NAME = "Id";
IDynamoDBContext DDBContext { get; set; }
///
/// Default constructor that Lambda will invoke.
///
public Functions()
{
// Check to see if a table name was passed in through environment variables and if so
// add the table mapping.
var tableName = System.Environment.GetEnvironmentVariable(TABLENAME_ENVIRONMENT_VARIABLE_LOOKUP);
if(!string.IsNullOrEmpty(tableName))
{
AWSConfigsDynamoDB.Context.TypeMappings[typeof(Blog)] = new Amazon.Util.TypeMapping(typeof(Blog), tableName);
}
var config = new DynamoDBContextConfig { Conversion = DynamoDBEntryConversion.V2 };
this.DDBContext = new DynamoDBContext(new AmazonDynamoDBClient(), config);
}
///
/// Constructor used for testing passing in a preconfigured DynamoDB client.
///
///
///
public Functions(IAmazonDynamoDB ddbClient, string tableName)
{
if (!string.IsNullOrEmpty(tableName))
{
AWSConfigsDynamoDB.Context.TypeMappings[typeof(Blog)] = new Amazon.Util.TypeMapping(typeof(Blog), tableName);
}
var config = new DynamoDBContextConfig { Conversion = DynamoDBEntryConversion.V2 };
this.DDBContext = new DynamoDBContext(ddbClient, config);
}
///
/// A Lambda function that returns back a page worth of blog posts.
///
///
/// The list of blogs
public async Task GetBlogsAsync(APIGatewayProxyRequest request, ILambdaContext context)
{
context.Logger.LogLine("Getting blogs");
var search = this.DDBContext.ScanAsync(null);
var page = await search.GetNextSetAsync();
context.Logger.LogLine($"Found {page.Count} blogs");
var response = new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.OK,
Body = JsonConvert.SerializeObject(page),
Headers = new Dictionary { { "Content-Type", "application/json" } }
};
return response;
}
///
/// A Lambda function that returns the blog identified by blogId
///
///
///
public async Task GetBlogAsync(APIGatewayProxyRequest request, ILambdaContext context)
{
string blogId = null;
if (request.PathParameters != null && request.PathParameters.ContainsKey(ID_QUERY_STRING_NAME))
blogId = request.PathParameters[ID_QUERY_STRING_NAME];
else if (request.QueryStringParameters != null && request.QueryStringParameters.ContainsKey(ID_QUERY_STRING_NAME))
blogId = request.QueryStringParameters[ID_QUERY_STRING_NAME];
if (string.IsNullOrEmpty(blogId))
{
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.BadRequest,
Body = $"Missing required parameter {ID_QUERY_STRING_NAME}"
};
}
context.Logger.LogLine($"Getting blog {blogId}");
var blog = await DDBContext.LoadAsync(blogId);
context.Logger.LogLine($"Found blog: {blog != null}");
if (blog == null)
{
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.NotFound
};
}
var response = new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.OK,
Body = JsonConvert.SerializeObject(blog),
Headers = new Dictionary { { "Content-Type", "application/json" } }
};
return response;
}
///
/// A Lambda function that adds a blog post.
///
///
///
public async Task AddBlogAsync(APIGatewayProxyRequest request, ILambdaContext context)
{
var blog = JsonConvert.DeserializeObject(request?.Body);
blog.Id = Guid.NewGuid().ToString();
blog.CreatedTimestamp = DateTime.Now;
context.Logger.LogLine($"Saving blog with id {blog.Id}");
await DDBContext.SaveAsync(blog);
var response = new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.OK,
Body = blog.Id.ToString(),
Headers = new Dictionary { { "Content-Type", "text/plain" } }
};
return response;
}
///
/// A Lambda function that removes a blog post from the DynamoDB table.
///
///
public async Task RemoveBlogAsync(APIGatewayProxyRequest request, ILambdaContext context)
{
string blogId = null;
if (request.PathParameters != null && request.PathParameters.ContainsKey(ID_QUERY_STRING_NAME))
blogId = request.PathParameters[ID_QUERY_STRING_NAME];
else if (request.QueryStringParameters != null && request.QueryStringParameters.ContainsKey(ID_QUERY_STRING_NAME))
blogId = request.QueryStringParameters[ID_QUERY_STRING_NAME];
if (string.IsNullOrEmpty(blogId))
{
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.BadRequest,
Body = $"Missing required parameter {ID_QUERY_STRING_NAME}"
};
}
context.Logger.LogLine($"Deleting blog with id {blogId}");
await this.DDBContext.DeleteAsync(blogId);
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.OK
};
}
}
}