티스토리 뷰

학습/AWS

그거 Lambda로 하면

aigoia 2024. 9. 14. 16:38

 

 몽고 DB를 써도 서버를 올려야 하나 보다. 그럼 그냥 Lambda로 하는게 편할듯 싶긴 하다. 람다를 쓰면 그냥 C#으로 작성하면 더 편하다. 

 

 AWS Lambda + DynamoDB로 갈지 AWS Lambda + MongoDB로 갈지만 정하면 되고 그냥 코드는 C#으로 짜자. 

 

 

 

 

 이거 보니까 으음 이것만 잘 연결해 주면 C#으로 짜서 MongoDB에 연결하는 거는 별 어려움이 없어 보인다. 

 

 C#으로 짤수도 있긴 한데 node.js로 짜면 그냥 쌩 node.js로 짜는 것보다는 express로 짜는게 더 직관적인거 같다. 이번에 써보니까 그렇더라. 

 

 그냥 쌩 node.js로 짜는 것보다 express로 짜는게 편하다. 

import express, {request, response} from 'express'
import mongoose from 'mongoose'
import dotenv from 'dotenv'
import { Product } from './models/productModel.js'

dotenv.config();
const app = express()
app.use(express.json())
const port = 3000

mongoose.connect(process.env.DATABASE_URL)
    .then(() => console.log('Connected to MongoDB Atlas'))
    .catch(error => console.log('Error connecting to MongoDB:', error))
app.listen(port, () => console.log(`Node is running on port ${port}`))

app.get('/collection', async (request, response) => {
    try {
        const collections = await mongoose.connection.db.listCollections().toArray()
        const collectionNames = collections.map(collection => collection.name)
        response.status(200).json(collectionNames)
    } catch (error) {
        console.log('Error fetching collections:', error)
        response.status(500).json({ message: error.message })
    }
})

app.get('/product', async (request, response) => {
    try {
        const product = await Product.find()
        response.status(200).json(product)
    } 
    catch (error) {
        console.log(error.message)
        response.status(500).json({ message: error.message })
    }
})

app.get('/product/:id', async (request, response) => {
    try {
        const id = request.params.id 
        const product = await Product.findById(id)
        if (!product) return response.status(404).json({ massage: `can not find product by ${id}`})
        response.status(200).json(product)
    }
    catch (error) {
        console.log(error.message)
        response.status(500).json({ message: error.message })
    }
})

app.delete('/product/:id', async (request, response) => {
    try {
        const id = request.params.id
        const product = await Product.findOneAndDelete(id)
        if (!product) return response.status(404).json({ massage: `can not find product by ${id}`})
        response.status(200).json(product)    
        
    }
    catch (error) {
        console.log(error.message)
        response.status(500).json({ message: error.message })
    }
})

app.put('/product/:id', async(request, response) => {
    try {
        const id = request.params.id
        const product = await Product.findByIdAndUpdate(id, request.body)
        if (!product) return response.status(404).json({ massage: `can not find product by ${id}`})
        response.status(200).json(product)
    }
    catch (error) {
        console.log(error.massage)
        response.status(500).json({ massage: error.massage })
    }
})
    

app.post('/product', async(request, response) => {
    try {
        const product = await Product.create(request.body)
        response.status(200).json(product)    
    } 
    catch (error) {
        console.log(error.message)   
        response.status(500).json({ message: error.message })
    }
})

 

 확실히 쌩 node.js로 짜는 것보다 편한거 같다. 

using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Threading.Tasks;

[Route("api/[controller]")]
    [ApiController]
public class ProductController : ControllerBase
{
    private readonly IMongoCollection<Product> _products;

    public ProductController(IMongoClient client)
    {
        var database = client.GetDatabase("YourDatabaseName");
        _products = database.GetCollection<Product>("Products");
    }

    [HttpGet]
    public async Task<ActionResult<List<Product>>> Get()
    {
        var products = await _products.Find(product => true).ToListAsync();
        return Ok(products);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> Get(string id)
    {
        var product = await _products.Find<Product>(p => p.Id == id).FirstOrDefaultAsync();
        if (product == null)
            return NotFound();
        return Ok(product);
    }

    [HttpPost]
    public async Task<ActionResult<Product>> Create(Product product)
    {
        await _products.InsertOneAsync(product);
        return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
    }

    [HttpPut("{id}")]
    public async Task<ActionResult> Update(string id, Product product)
    {
        var result = await _products.ReplaceOneAsync(p => p.Id == id, product);
        if (result.MatchedCount == 0)
            return NotFound();
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<ActionResult> Delete(string id)
    {
        var result = await _products.DeleteOneAsync(p => p.Id == id);
        if (result.DeletedCount == 0)
            return NotFound();
        return NoContent();
    }
}

public class Product
{
    public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

 

 GPT에 같은 코드를 C#으로 짜면 어쩌냐고 물어보니까 이렇게 하라고 주더라.  

 

 이거 node.js보다 C#이 더 직관적인거 같긴 하다. 물론 거는 내가 C#사용자 여서 그럴수도 있다. 

 

ASP.NET Core의 주요 응답 메서드

  • Ok():
    • 상태 코드 200(OK)을 가진 성공적인 응답을 생성합니다. 선택적으로 응답 본문을 제공할 수 있습니다.
    • 예: return Ok(product);
  • NotFound():
    • 상태 코드 404(Not Found)를 가진 응답을 생성합니다. 요청한 리소스를 찾을 수 없을 때 사용됩니다.
    • 예: return NotFound();
  • Created():
    • 상태 코드 201(Created)을 가진 응답을 생성합니다. 새 리소스가 성공적으로 생성되었음을 나타냅니다.
    • 예: return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
  • BadRequest():
    • 상태 코드 400(Bad Request)을 가진 응답을 생성합니다. 클라이언트의 요청이 잘못되었을 때 사용됩니다.
    • 예: return BadRequest("Invalid request.");
  • NoContent():
    • 상태 코드 204(No Content)를 가진 응답을 생성합니다. 요청은 성공했지만 응답 본문이 없는 경우 사용됩니다.
    • 예: return NoContent();
  • StatusCode(int statusCode):
    • 사용자 정의 상태 코드를 가진 응답을 생성할 수 있습니다.
    • 예: return StatusCode(418, "I'm a teapot");

 GPT가 이런건 미리 다 만들어져 있다고 이야기 해준다. 요거 읽어보니까  Post를 했을때 200이 아니라  201을 반환해야 하는거 같다. 

 

 

https://aigoia.tistory.com/search/DynamoDB

 

Goetita

 

aigoia.tistory.com

 예전에 코드를 보고 있는데 확실히 자바스크립트로 쌩으로 짜는 것보다. mongoose와 express를 쓰는게 더 직관적인거 같다. 그리고 다시 보니까 왠지 MongoDB가 좀더 직관적인거 같기도 하고 아리송송하다. 이게 내가 할수 있다가 아니라 그래서 가르쳐서 넘겨 줄수 있냐가 관건이기 때문이다. 

 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;

// 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 HelloWorld
{
    public class Function
{
    static HttpClient Client => new();

    static async Task<string> GetCallingIp()
{
    Client.DefaultRequestHeaders.Accept.Clear();
    Client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client");

    var massage = await Client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false);

    return massage.Replace("\n","");
}

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest eventPayload, ILambdaContext context)
{
    if (string.IsNullOrEmpty(eventPayload.Body))
{
    return new APIGatewayProxyResponse
{
    Body = "Invalid request: Body is null or empty",
    StatusCode = 400,
    Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
}
    try
    {
        var eventToJob = JsonSerializer.Deserialize<Job>(eventPayload.Body);

        if (string.IsNullOrEmpty(eventToJob.Title))
        {
            return new APIGatewayProxyResponse
            {
                Body = "Invalid request: Deserialize error",
                    StatusCode = 500,
                    Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
            };
        }

        if (eventPayload.RequestContext.HttpMethod.ToUpper() == "GET")
        {
            var dynamoContext = new DynamoDBContext(new AmazonDynamoDBClient());
            var jobContext = await dynamoContext.LoadAsync<Job>(eventToJob.Title);

            var location = await GetCallingIp();
            var body = new Dictionary<string, string>
            {
                { "Job", jobContext.Title},
                { "Job description", jobContext.Description}
            };

            return new APIGatewayProxyResponse
            {
                Body = JsonSerializer.Serialize(body),
                    StatusCode = 200,
                    Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
            };
        }

        return new APIGatewayProxyResponse
        {
            Body = $"Error occurred: POST is not made yet",
            StatusCode = 500,
            Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
        };
    }
    catch (Exception exception)
    {
        return new APIGatewayProxyResponse
        {
            Body = $"Error occurred: {exception.Message}",
            StatusCode = 500,
            Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
        };
    }
}
}

    public class Job
{
    [DynamoDBHashKey]
    public string Title { get; set; }
    public string Description { get; set; }

    public Job() { }
}

 

 와 전에 짠 코드 보고 있는데 이거랑 비교해 보니 개어렵게 짰다. 이게 프레임 워크 없이 쌩 날로 짜면 이렇구나. 프레임워크를 쓰기는 써야 하는거 같다. 챗GPT도 모르고 강의도 없을때라 공식문서 보면서 짲었던 기억이난다. 

 

 C#을 쓰면 ASP net core를 쓰긴 써야 겠구나.

using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Add DynamoDB client
builder.Services.AddSingleton<IAmazonDynamoDB>(sp =>
{
    var config = builder.Configuration.GetSection("AWS");
    return new AmazonDynamoDBClient(
        config["AccessKeyId"],
        config["SecretAccessKey"],
        Amazon.RegionEndpoint.GetBySystemName(config["Region"]));
});

builder.Services.AddScoped<IDynamoDBContext, DynamoDBContext>();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseAuthorization();

app.MapControllers();

app.Run();

 

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.DynamoDBv2.DataModel;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Text.Json;

namespace MyWebApi.Controllers
{
    [ApiController]
        [Route("api/[controller]")]
    public class JobsController : ControllerBase
    {
        private readonly IDynamoDBContext _dynamoDbContext;
        private readonly ILogger<JobsController> _logger;

        public JobsController(IDynamoDBContext dynamoDbContext, ILogger<JobsController> logger)
        {
            _dynamoDbContext = dynamoDbContext;
            _logger = logger;
        }

        // GET api/jobs/{title}
        [HttpGet("{title}")]
        public async Task<ActionResult<Job>> Get(string title)
        {
            if (string.IsNullOrEmpty(title))
            {
                return BadRequest("Invalid request: Title is null or empty");
            }

            try
            {
                var job = await _dynamoDbContext.LoadAsync<Job>(title);
                if (job == null)
                {
                    return NotFound($"Job with title {title} not found");
                }

                return Ok(job);
            }
            catch (System.Exception ex)
            {
                _logger.LogError(ex, "Error occurred while fetching job");
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }

        // POST api/jobs
        [HttpPost]
        public async Task<ActionResult<Job>> Post([FromBody] Job job)
        {
            if (job == null || string.IsNullOrEmpty(job.Title))
            {
                return BadRequest("Invalid request: Job or Title is null or empty");
            }

            try
            {
                await _dynamoDbContext.SaveAsync(job);
                return CreatedAtAction(nameof(Get), new { title = job.Title }, job);
            }
            catch (System.Exception ex)
            {
                _logger.LogError(ex, "Error occurred while creating job");
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
        }
    }

    [DynamoDBTable("Jobs")]
    public class Job
{
    [DynamoDBHashKey]
    public string Title { get; set; }
    public string Description { get; set; }

    public Job() { }
}
}

 

 GPT가 앞으로 이렇게 짜라고 알려주었다. 보니까 프레임 워크를 쓰지 않는 코드는 말그대로 빈 편지지 json에다가 기록을 해서 보내는 거고 ASP는 확실히 한번 더 추상화가 된거 같다. 

 

일단은 그냥 진행하자. 

 

 

'학습 > AWS' 카테고리의 다른 글

AWS EC2 서버 SSH로 접속하기  (0) 2025.03.17
공부는 CRUD만 하자  (2) 2024.09.13
자유자제로 다룰수 없으면 아는게 아니다  (0) 2024.09.13
몽고 DB 후반전  (0) 2024.09.12
더 짧은 이걸로 해야 겠다  (0) 2024.09.12