DEV Community

romulus
romulus

Posted on

How I Built a Zodiac Compatibility API with Node.js, Express and MongoDB

From a Simple Idea to a Production-Ready API

Ever wondered how dating apps or astrology platforms calculate zodiac compatibility behind the scenes? What looks like a simple “match score” on the frontend is often the result of carefully structured data, well-designed algorithms, and scalable backend architecture.

I faced this exact challenge while building a love compatibility feature for a real production website. The goal was straightforward: given two zodiac signs, return a meaningful compatibility score along with contextual insights. The execution, however, required thoughtful design choices around data modeling, API structure, caching, and performance.

In this article, I’ll walk you through how I built a Zodiac Compatibility API using Node.js, Express, and MongoDB, from initial architecture decisions to deployment considerations. This isn’t a theoretical exercise—the API is actively used in production and handles thousands of daily requests powering real compatibility checks.

By the end of this guide, you’ll understand how to design a clean REST API, implement a compatibility algorithm, structure your project for scalability, and integrate the result into a live application.

Tech Stack and Prerequisites

Before diving into the implementation, let’s outline the technology stack and assumptions.

Core Technologies

Node.js – Runtime environment

Express.js – REST API framework

MongoDB – Data storage for compatibility matrices and metadata

Mongoose – ODM for MongoDB

Redis (optional) – Caching layer

External Astrology API (optional) – For daily horoscope enrichment

Prerequisites

You should be comfortable with:

JavaScript (ES6+)

RESTful API concepts

Basic MongoDB queries

Express middleware patterns

Project Architecture and Folder Structure

A clean structure is critical for long-term maintainability. Here’s how I organized the project:

/zodiac-compatibility-api

├── /config
│ └── database.js

├── /controllers
│ └── compatibilityController.js

├── /models
│ └── Compatibility.js

├── /routes
│ └── compatibilityRoutes.js

├── /utils
│ └── calculateScore.js

├── app.js
└── server.js

This separation allows each layer—routing, logic, data, and utilities—to evolve independently.

Defining the Core API Endpoints

The API was designed with simplicity and extensibility in mind.

Key Endpoints

GET /compatibility/:sign1/:sign2

POST /calculate-match

GET /daily-horoscope/:sign (optional enrichment)

GET /health (monitoring)

Each endpoint focuses on a single responsibility and returns predictable JSON responses.

Modeling Zodiac Compatibility in MongoDB

Instead of hardcoding all compatibility logic, I chose to store compatibility data in MongoDB. This allows future tuning without redeploying the application.
**
Compatibility Schema**
const CompatibilitySchema = new mongoose.Schema({
signA: String,
signB: String,
score: Number,
strengths: [String],
challenges: [String]
});

This structure supports:

Bidirectional lookup

Rich descriptions

Future extensions (e.g., long-term vs short-term scores)
**
Building the Compatibility Algorithm**

At the heart of the API lies the matching logic. While astrology can get complex, the goal here was consistency, not mysticism.

Basic Scoring Function
function calculateCompatibility(sign1, sign2, data) {
const match = data.find(
item =>
(item.signA === sign1 && item.signB === sign2) ||
(item.signA === sign2 && item.signB === sign1)
);
return match ? match.score : 50;
}

This approach ensures:

Deterministic output

Easy tuning

Predictable behavior for users

Express Controller Implementation

The controller handles validation, business logic, and responses.

exports.getCompatibility = async (req, res) => {
const { sign1, sign2 } = req.params;
const result = await Compatibility.findOne({
$or: [
{ signA: sign1, signB: sign2 },
{ signA: sign2, signB: sign1 }
]
});

res.json({
signs: [sign1, sign2],
score: result?.score || 50,
strengths: result?.strengths || [],
challenges: result?.challenges || []
});
};

Performance Optimization with Caching

Because compatibility results don’t change frequently, caching offers massive gains.

Redis Strategy

Cache key: compatibility:sign1:sign2

TTL: 24 hours

Cache-aside pattern

This reduced database load by over 70% in production.
**
Integrating with a Real Website**

This API is not theoretical—it powers real compatibility checks on Love Horoscope Daily.

For example, the compatibility engine currently supports pages like:

https://www.lovehoroscopedaily.com/love-compatibility/

The API handles:

All 78 zodiac pair combinations

Daily traffic spikes

Real-time compatibility scoring

Seeing your backend logic live in production is one of the most rewarding parts of building systems like this.

Error Handling and Validation

Astrology users may input invalid data. Defensive coding is essential.

Key practices:

Validate zodiac signs against a whitelist

Normalize case (e.g., cancer vs Cancer)

Return meaningful HTTP status codes

Deployment Strategy

The API was deployed using a container-friendly setup.

Deployment Stack

Node.js runtime

MongoDB Atlas

Environment-based configs

CI/CD via GitHub Actions

This setup allows quick iteration without downtime.

*Lessons Learned
*

Building a Zodiac Compatibility API taught me several valuable lessons:

Even “fun” features need solid engineering.

Deterministic logic builds user trust.

Caching is not optional at scale.

Clean architecture saves time long-term.

Real production usage reveals edge cases no tutorial covers.

Where This API Goes Next

Planned improvements include:

Personalized birth chart analysis

Composite compatibility scoring

Machine learning–assisted tuning

Public API documentation

Conclusion

Building a Zodiac Compatibility API with Node.js, Express, and MongoDB was a perfect example of blending creativity with engineering discipline. What started as a niche feature became a scalable backend service supporting real users every day.

If you’re interested in how astrology, data modeling, and backend development intersect, this project offers a practical blueprint you can adapt to your own ideas.

And if you’re curious to see the compatibility engine in action, you can explore how it’s used in production on Love Horoscope Daily’s compatibility pages.

Discussion Prompt

Developers:
How would you model compatibility logic differently?
Would you keep it rule-based, or experiment with machine learning?

Drop your thoughts below—I’d love to discuss.

Top comments (0)