I’ve always been fascinated by how ancient civilizations tracked the movement of stars and planets with remarkable precision—thousands of years ago, without computers or telescopes, they knew exactly where celestial bodies would be. That knowledge feels almost magical, yet it was built on careful observation and mathematics.

When I wanted to build something that could answer “where is Mars right now?” or “when does the Moon rise tonight?”, I was surprised by how difficult it was to find a straightforward API that just gave me the data. Most options were either overly simplified or required wading through astronomical jargon and complex setups. I wanted the precision of professional astronomy software with the simplicity of a REST API.

That’s why I built Moon.

What It Does

Moon is an Azure Function that answers questions about celestial bodies. Want to know where Jupiter is in the sky right now? Just make a GET request. Need rise and set times for Venus from your exact location? Send a POST with your coordinates. It handles nine celestial bodies—the Moon and the visible planets—and gives you everything from basic positioning to detailed astronomical calculations.

The interesting part was figuring out how to get professional-grade accuracy without making the API complicated to use. I ended up combining three different Python astronomy libraries—PyEphem for fast event predictions, Skyfield for high-precision positioning, and Astropy for constellation tracking. Each library is good at different things, so using all three together gives you NASA-level accuracy with simple HTTP requests.

Using the API

The simplest case is just asking “where is this thing right now?”:

curl https://your-function-app.azurewebsites.net/api/moon

You get back everything you’d want to know—position in the sky (altitude and azimuth), distance from Earth, when it rises and sets, what constellation it’s in, and for the Moon specifically, the current phase. All calculated for right now, from a default location.

But the more interesting use case is asking from your specific location. If you’re standing in Los Angeles and want to know where Mars is in your sky, you POST your coordinates:

curl -X POST https://your-function-app.azurewebsites.net/api/mars \
  -H "Content-Type: application/json" \
  -d '{
    "latitude": 34.0522,
    "longitude": -118.2437,
    "elevation": 100
  }'

The calculations account for your exact position on Earth—this is called topocentric correction, and it matters more than you’d think. The difference between where Saturn appears from New York versus from Sydney can be significant, especially for closer objects like the Moon.

Why Build This?

Honestly, I just think it’s cool that we can calculate where planets will be with such precision. Ancient astronomers spent lifetimes making tables of planetary positions. Now we have ephemeris data from NASA that’s accurate to arcseconds, and we can serve it up through a simple API call.

I also wanted something I could use for my own projects without having to install heavy astronomy software or deal with complicated Python notebooks every time. Sometimes you just want an API endpoint that tells you when Saturn rises tonight.

How It’s Built

The code uses a registry pattern that makes it easy to add new celestial bodies. Each body gets its own calculator class that inherits from a base calculator:

@register_body("pluto")
class PlutoCalculator(BaseCalculator):
    def calculate(self, observer_lat, observer_lon, elevation):
        # Implementation
        return astronomical_data

This keeps everything modular. When you hit /api/mars, the registry looks up the Mars calculator and runs it. Adding support for a new body is just writing a new calculator class and registering it.

The Azure Function setup means it scales automatically and you only pay for what you use. Most requests come back in under half a second, which is plenty fast for this kind of data.

The Details That Matter

One thing I learned while building this: astronomical calculations have a lot of subtle complexity. For example, there are different time scales—UTC for what we see on clocks, UT1 for Earth’s actual rotation, and TT (Terrestrial Time) for the mathematical models. The libraries handle all that, but you need to know which one to use when.

The calculations also account for atmospheric refraction—the way Earth’s atmosphere bends light. This is especially important when objects are near the horizon. The Moon can appear to rise several minutes earlier than the “geometric” calculation would suggest, just because of how our atmosphere bends its light.

All of this runs on NASA JPL ephemeris data, which is absurdly precise. We’re talking arcsecond-level accuracy for modern dates.

What’s Next

I’d like to add satellite tracking at some point—knowing when the ISS passes over would be useful. Deep sky objects like the Messier catalog would be interesting too, though those don’t move like planets do.

The other feature I keep thinking about is historical queries. Right now it calculates “now,” but it would be cool to ask “where was Mars on January 1, 1900?” The libraries support it; I just haven’t exposed it through the API yet.

Try It Out

The code is open source under the MIT License and available on GitHub. If you want to run your own instance, it’s just a matter of deploying the Azure Function and hitting the endpoints.

I built this because I wanted it to exist. If you’ve ever wondered where planets are in the sky, or if you’re building something that needs astronomical data, maybe you’ll find it useful too.


Check out the Moon repository on GitHub