Categories
Uncategorized

Building Which-Fuji: A Side Project for Fujifilm Camera Enthusiasts

I’ve been quietly working on a small side project for the last few weeks, and it’s finally at a point where I can share it properly.

Which-Fuji is a tiny website I built to help people figure out which Fujifilm camera to buy. That’s it. No reviews, no affiliate spam, no walls of text — just a few different paths to a good answer depending on what you actually care about.

Why I built it

Every time a friend or family member asked me “which camera should I get?”, I’d end up sending the same three-paragraph essay over WhatsApp explaining the differences between the X-T series, the X-H series, and so on. I figured if I kept writing the same thing, I might as well put it on a website so I can just send a link.

Beyond being a useful page for other people, it was also a fun excuse to:

  • Build a small content site without dragging in a CMS
  • Practice writing structured data and sitemaps properly
  • See how a fresh .xyz domain fares in Google Search Console
  • Keep the whole thing small enough that I can iterate quickly

What’s on the site

If you head over to which-fuji.xyz, you’ll find a few different entry points:

  • browse page listing the cameras with quick filters
  • A short quiz that recommends a model based on what you shoot
  • Reviews for each camera — short, honest, no fluff
  • A couple of longer-form articles for the curious

It’s deliberately not trying to be a comprehensive review site like DPReview or PetaPixel. Those exist. This is more like a friend’s recommendation, written down.

Tech notes

The site is built on Cloudflare Pages with a static-first architecture. There’s a small llms.txt and llms-full.txt at the root if you’re an AI crawler and want the structured version, plus a normal sitemap.xml and a robots.txt that explains the policy clearly. The robots file is unusually explicit because I wanted to be upfront about which bots are welcome.

What I learned (so far)

A few things surprised me:

  1. A fresh domain with zero backlinks is invisible to Google. Even with a valid sitemap and a working robots.txt, Search Console reports “URL is unknown” until something on the wider web points at you. Indexing is gated on discovery.
  2. Cloudflare’s default robots.txt template is genuinely good. It blocks the noisy AI scrapers while keeping the useful ones (and search bots) allowed.
  3. Static sites still win for content. No databases, no servers to babysit, no deploys longer than 30 seconds. The whole thing costs me nothing to run.

I’ll probably write more about the SEO side of things once Google has actually had a chance to crawl it — there are a few experiments I want to run.

Try it out

If you’re shopping for a Fujifilm camera — or just curious about what came out of one too many late-night WhatsApp conversations — take a look at which-fuji.xyz. Feedback is welcome; you can find me on the usual places.

Categories
General Python

Auto incrementing IDs for MongoDB

If you’re familiar with relational databases like MySQL or PostgreSQL, you’re probably also familiar with auto incrementing IDs. You select a primary key for a table and make it auto incrementing. Every row you insert afterwards, each of them gets a new ID, automatically incremented from the last one. We don’t have to keep track of what number comes next or ensure the atomic nature of this operation (what happens if two different client wants to insert a new row at the very same time? do they both get the same id?). This can be very useful where sequential, numeric IDs are essential. For example, let’s say we’re building a url shortener. We can base62 encode the ID of the url id to quickly generate a short slug for that long url.

Fast forward to MongoDB, the popular NoSQL database doesn’t have any equivalent to sequential IDs. It’s true that you can insert anything unique as the required _id field of a mongodb document, so you can take things to your hand and try to insert unique ids yourselves. But you have to ensure the uniqueness and atomicity of the operation.

A very popular work around to this is to create a separate mongodb collection. Then maintain documents with a numeric value to keep track of your auto incrementing IDs. Now, every time we want to insert a new document that needs a unique ID, we come back to this collection, use the $inc operator to atomically increment this number and then use the incremented number as the unique id for our new document.

Let me give an example, say we have an messages collection. Each new message needs a new, sequential ID. We create a new collection named sequences. Each document in this sequences collection will hold the last used ID for a collection. So, for tracking the unique ID in the messages collection, we create a new document in the sequences collection like this:

Next, we will write a function that can give us the next sequential ID for a collection by it’s name. The code is in Python, using PyMongo library.

If we need the next auto incrementing ID for the messages collection, we can call it like this:

Find and Modify – Deprecated

If you have searched on Google, you might have come across many StackOverflow answers as well as individual blog posts which refer to findAndModify() call (find_and_modify in Pymongo). This was the way to do things. But it’s deprecated now, so please use the new find_one_and_update function now.

(How) Does this scale?

We would only call the get_sequence function before inserting a new mongo document. The function uses the $inc operator which is atomic in nature. Mongo guarantees this. So even if 100s of different clients trying to increment the value for the same document, they will be all applied one after one. So each value they get will be unique, new IDs.

I personally haven’t been able to test this strategy at a larger scale but according to people on StackOverflow and other forums, people have scaled this to thousands and millions of users. So I guess it’s pretty safe.

Categories
Python

API Star: Python 3 API Framework

For building quick APIs in Python, I have mostly depended on Flask. Recently I came across a new API framework for Python 3 named “API Star” which seemed really interesting to me for several reasons. Firstly the framework embraces modern Python features like type hints and asyncio. And then it goes ahead and uses these features to provide awesome development experience for us, the developers. We will get into those features soon but before we begin, I would like to thank Tom Christie for all the work he has put into Django REST Framework and now API Star.

Now back to API Star – I feel very productive in the framework. I can choose to write async codes based on asyncio or I can choose a traditional backend like WSGI. It comes with a command line tool – apistar to help us get things done faster. There’s (optional) support for both Django ORM and SQLAlchemy.  There’s a brilliant type system that enables us to define constraints on our input and output and from these, API Star can auto generate api schemas (and docs), provide validation and serialization feature and a lot more. Although API Star is heavily focused on building APIs, you can also build web applications on top of it fairly easily. All these might not make proper sense until we build something all by ourselves.

Getting Started

We will start by installing API Star. It would be a good idea to create a virtual environment for this exercise. If you don’t know how to create a virtualenv, don’t worry and go ahead.

If you’re not using a virtual environment or the pip command for your Python 3 is called pip3, then please use pip3 install apistar instead.

Once we have the package installed, we should have access to the apistar command line tool. We can create a new project with it. Let’s create a new project in our current directory.

Now we should have two files created – app.py – which contains the main application and then test.py for our tests. Let’s examine our app.py file:

Before we dive into the code, let’s run the app and see if it works. If we navigate to http://127.0.0.1:8080/ we will get this following response:

And if we navigate to: http://127.0.0.1:8080/?name=masnun

Similarly if we navigate to: http://127.0.0.1:8080/docs/, we will see auto generated docs for our API.

Now let’s look at the code. We have a welcome function that takes a parameter named name which has a default value of None. API Star is a smart api framework. It will try to find the name key in the url path or query string and pass it to our function. It also generates the API docs based on it. Pretty nice, no?

We then create a list of Route and Include instances and pass the list to the App instance. Route objects are used to define custom user routing. Include , as the name suggests, includes/embeds other routes under the path provided to it.

Routing

Routing is simple. When constructing the App instance, we need to pass a list as the routes argument. This list should comprise of Route or Include objects as we just saw above. For Routes, we pass a url path, http method name and the request handler callable (function or otherwise). For the Include instances, we pass a url path and a list of Routes instance.

Path Parameters

We can put a name inside curly braces to declare a url path parameter. For example /user/{user_id} defines a path where the user_id is a path parameter or a  variable which will be injected into the handler function (actually callable). Here’s a quick example:

If we visit http://127.0.0.1:8080/user/23 we will get a response like this:

But if we try to visit http://127.0.0.1:8080/user/some_string – it will not match. Because the user_profile function we defined, we added a type hint for the user_id parameter. If it’s not integer, the path doesn’t match. But if we go ahead and delete the type hint and just use user_profile(user_id), it will match this url. This is again API Star is being smart and taking advantages of typing.

Including / Grouping Routes

Sometimes it might make sense to group certain urls together. Say we have a user module that deals with user related functionality. It might be better to group all the user related endpoints under the /user path. For example – /user/new, /user/1, /user/1/update and what not. We can easily create our handlers and routes in a separate module or package even and then include them in our own routes.

Let’s create a new module named user, the file name would be user.py. Let’s put these codes in this file:

Now we can import our user_routes from within our main app file and use it like this:

Now /user/new will delegate to user_new function.

Accessing Query String / Query Parameters

Any parameters passed in the query parameters can be injected directly into handler function. Say for the url /call?phone=1234, the handler function can define a phone parameter and it will receive the value from the query string / query parameters. If the url query string doesn’t include a value for phone, it will get None instead. We can also set a default value to the parameter like this:

In the above example, we set a default value to name which is None anyway.

Injecting Objects

By type hinting a request handler, we can have different objects injected into our views. Injecting request related objects can be helpful for accessing them directly from inside the handler. There are several built in objects in the http package from API Star itself. We can also use it’s type system to create our own custom objects and have them injected into our functions. API Star also does data validation based on the constraints specified.

Let’s define our own User type and have it injected in our request handler:

Now if we send this request:

Guess what happens? We get an error saying age must be equal to or greater than 18. The type system is allowing us intelligent data validation as well. If we enable the docs url, we will also get these parameters automatically documented there.

Sending a Response

If you have noticed so far, we can just pass a dictionary and it will be JSON encoded and returned by default. However, we can set the status code and any additional headers by using the Response class from apistar. Here’s a quick example:

It should send a plain text response along with a custom header. Please note that the content should be bytes, not string. That’s why I encoded it.

Moving On

I just walked through some of the features of API Star. There’s a lot more of cool stuff in API Star. I do recommend going through the Github Readme for learning more about different features offered by this excellent framework. I shall also try to cover short, focused tutorials on API Star in the coming days.