Home > Software engineering >  POST Request of a JSON Array
POST Request of a JSON Array

Time:03-07

I am able to write a controller for posting 1 object to the database in my controller. However I want to now post multiple objects in 1 API call using JSON

My Entity

public class CustomerInvoiceLine: BaseEntity
    {
        public SchoolFee SchoolFee { get; set; }
        public int SchoolFeeId { get; set; }
        public string Description { get; set; }
        public int Quantity { get; set; }
        public int Amount { get; set; }
        public int CustomerInvoiceId { get; set; }
    }

I have a DTO as follows:

public class CustomerInvoiceLineAddDto
    {
        public int SchoolFeeId { get; set; }
        public string Description { get; set; }
        public int Quantity { get; set; }
        public int Amount { get; set; }
        public int CustomerInvoiceId { get; set; }
    }

I have created a Repository:

public async Task AddCustomerInvoiceLineAsync(CustomerInvoiceLine customerInvoiceLine)
        {
            _context.CustomerInvoiceLines.Add(customerInvoiceLine);
            await _context.SaveChangesAsync();
        }

And finally the Controller

[HttpPost]
        public async Task<ActionResult> AddCustomerInvoiceLine(CustomerInvoiceLineAddDto invoiceLineAddDto)
        {
            CustomerInvoiceLine invoiceLineDetails = new CustomerInvoiceLine();
            _mapper.Map(invoiceLineAddDto, invoiceLineDetails);
            await _unitOfWork.CustomerInvoiceLineRepository.AddCustomerInvoiceLineAsync(invoiceLineDetails);
            return Ok();
        }

The above controller works fine for posting just 1 item in the JSON request.

I then tried to change this to receive a JSON Array.

public async Task<ActionResult> AddCustomerInvoiceLine(CustomerInvoiceLineAddDto invoiceLineAddDto)
        {
            string json = "";
            CustomerInvoiceLine invoiceLineDetails = new CustomerInvoiceLine();
            CustomerInvoiceLineAddDto invoiceLines = JsonConvert.DeserializeObject<CustomerInvoiceLineAddDto>( json );
            _mapper.Map(invoiceLineAddDto, invoiceLines);
            await _unitOfWork.CustomerInvoiceLineRepository.AddCustomerInvoiceLineAsync(invoiceLineDetails);
            return Ok();
        }

My JSON Request:

[
    {
        "schoolFeeId": 1,
        "customerInvoiceId": 18,
        "description": "School Fees for 2022",
        "quantity": 1,
        "amount": 5000
    },
    {
        "schoolFeeId": 1,
        "customerInvoiceId": 18,
        "description": "School Fees for 2021",
        "quantity": 1,
        "amount": 3000
    }
]

Could somebody please assist with understanding how to deserialise the JSON body and then process to the database?

CodePudding user response:

If you want to accept an array, make sure the controller accepts an array. Then automapper is smart enough to convert an array of one type to an array of another type.

public async Task<ActionResult> AddCustomerInvoiceLine(CustomerInvoiceLineAddDto[] invoiceLinesAddDto)
{
    var invoiceLineDetails = _mapper.Map<List<CustomerInvoiceLine>>(invoiceLinesAddDto);
    await _unitOfWork.CustomerInvoiceLineRepository.AddCustomerInvoiceLinesAsync(invoiceLineDetails);
    return Ok();
}

In your unit of work, add a function to handle the adding of a list

public async Task AddCustomerInvoiceLinesAsync(IEnumerable<CustomerInvoiceLine> customerInvoiceLines)
{
    _context.CustomerInvoiceLines.AddRange(customerInvoiceLines);
    await _context.SaveChangesAsync();
}

Be advised, you can't make a single controller method to handle both the array request and the single item request. I would suggest to define two distinct endpoint so consumers of your api knows which needs an array and which one not.

  • Related