DEV Community

Ella
Ella

Posted on

I Built a Procurement Quotation Comparator API (Node.js + TypeScript)

Table of Contents


Introduction

Okay so lately I built this Comparator API that compares vendor quotations using a weighted scoring model to recommend the best vendor.

It’s been a really interesting journey, and I wanted to share how I built it and some of the things I learned along the way.

I also have this feeling that the project is actually useful. Instead of manually calculating vendor comparisons, you can just gather your vendor data in JSON format, send it to the API, and boom… you get the recommended vendor.

Boom GIF


Who Am I

Before I dive in…

Hi, my name is Ella.

I’m a developer who loves understanding the ins and outs of how applications work. Recently I’ve also been curious about the behind-the-scenes of successful apps, like why a certain idea works and how it’s implemented.

I plan to keep building projects, participating in challenges, and connecting with more developers who share similar interests.

I’m curious about almost everything in tech. While I enjoy experimenting, I currently really enjoy data-related work and backend development.

Maybe that will change in the future… maybe not 😅


Check Out My Other Work


You can also check out some of my other work on GitHub.

If you like what I build, feel free to support ⭐


Why I Built This

I built this project mainly to improve my Node.js and basic Express knowledge.

One of the biggest challenges I faced was getting the calculations right and making sure the scoring logic works correctly.

It sounds simple at first, but once you start thinking about:

  • normalization
  • cost vs benefit criteria
  • weighting systems

you realize there’s more thinking involved.


Tech Stack

Technology Purpose
Node.js Backend runtime
TypeScript Type safety
Express API framework

How the API Works

The API workflow is pretty simple.

  • Generate a template
  • Fill it with vendor data
  • Send it to the API
  • Get the recommended vendor

Steps

  • Generate a template from /sample-quotes
  • Customize the vendor data
  • Send the data to /analyze-quotes
  • The API calculates the results

Presentation GIF


Behind The Scenes (The Scoring Logic)

The API uses something called a Weighted Scoring Model.

Each vendor is evaluated using three criteria:

  • Price
  • Delivery time
  • Payment terms

These criteria have weights:

Criterion Weight
Price 0.5
Delivery Days 0.3
Payment Terms 0.2

Step 1: Normalize Price

Price is treated as a cost criterion.

That means lower values are better.

Formula:

PriceScore = MinimumPrice / VendorPrice
Enter fullscreen mode Exit fullscreen mode

price comparison image

From the image we can see that the lowest price vendor gets the best score.


Step 2: Normalize Delivery Days

Delivery time is also a cost criterion.

Formula:

DeliveryScore = MinimumDeliveryDays / VendorDeliveryDays
Enter fullscreen mode Exit fullscreen mode

delivery comparison image

The fastest delivery vendor wins here.


Step 3: Normalize Payment Terms

Payment terms are treated as a benefit criterion.

This means higher values are better.

Formula:

PaymentScore = VendorPaymentScore / MaximumPaymentScore
Enter fullscreen mode Exit fullscreen mode

The maximum value comes from:

scoringScale.paymentTermsScoreMax
Enter fullscreen mode Exit fullscreen mode

payment comparison image


Step 4: Calculate Weighted Score

After normalization, each score is multiplied by its assigned weight.

TotalScore =
(PriceWeight × PriceScore) +
(DeliveryWeight × DeliveryScore) +
(PaymentWeight × PaymentScore)
Enter fullscreen mode Exit fullscreen mode

The vendor with the highest total score becomes the recommended vendor.

final image


Endpoints

Health Check

GET /health
Enter fullscreen mode Exit fullscreen mode

Used to confirm the API is running.


Get Sample Template

GET /sample-quotes
Enter fullscreen mode Exit fullscreen mode

Returns a sample JSON template.


Analyze Quotes

POST /analyze-quotes
Enter fullscreen mode Exit fullscreen mode

Processes vendor quotations and calculates the best option.

⚠️ Important

  • Use raw JSON
  • Field names must remain the same
  • You can add more vendors to the vendors array

Example Template

{
  "projectName": "projectName",
  "currency": "USD",
  "scoringScale": {
    "paymentTermsScoreMax": 10
  },
  "weighting": {
    "price": 0.5,
    "deliveryDays": 0.3,
    "paymentTermsScore": 0.2
  },
  "vendors": [
    {
      "name": "Vendor A",
      "price": 100000,
      "deliveryDays": 30,
      "paymentTermsScore": 8
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Required Fields

The following fields must exist:

  • vendors
  • scoringScale
  • weighting

If any are missing the API returns 400 Bad Request.


My Review

I had fun building this project.

It involved:

  • research
  • learning procurement concepts
  • implementing scoring logic

I'd rate it 7/10 mainly because I used sample data throughout the project.

Duration

It took me about 2 days to build.

At first I thought it would be simple… but I quickly realized I needed to properly understand the scoring model.


Next Steps

Things I want to explore next:

  • [ ] Get real procurement users to test it
  • [ ] Improve the scoring model
  • [ ] Deploy the API
  • [ ] Add more evaluation criteria

Terms I Learned

Procurement
The process of sourcing and purchasing goods or services from suppliers.

Weighting
A way to assign importance to each evaluation criterion.

Cost Criterion
A factor where lower values are better.

Examples:

Price

Delivery days


Benefit Criterion
A factor where higher values are better.

Example:

Payment terms score


Weighted Score
The final score for a vendor after multiplying each normalized value by its weight.

Minimum Price Value

The lowest vendor price used to normalize price scores.


Minimum Delivery Value

The fastest delivery time among vendors.


Payment Score

A normalized score calculated using:

PaymentScore = VendorScore / MaxScore
Enter fullscreen mode Exit fullscreen mode

This converts values into a 0–1 scale.



Final Thoughts

This project helped me understand how decision models and backend logic can work together.

If you have feedback, I'd really appreciate it.

Thanks for reading ❤️.

Top comments (0)