👋 Next.js Conf 2024: Come build, party, run, and connect with us! See all events

Foodsteps

By Kristoffer Brabrand

App with recipes and food courses from the chefs at Kulinarisk Akademi (the culinary academy) in Oslo. Sanity+Mux powered app built in React/React Native.

Marketing site where vouchers and subscriptions can be purchased
Step-by-step recipes in the app
Profiteroles course in the app
Custom field for auto-filling measurements for recipes. Dubbed «the wizard button» by the chefs

About the project

In the beginning of the project the only thing we knew was that we didn't know what the end product would look like, so having a flexible and scalable content model was important. Sanity was more or less given, and we started out building a simple content model for recipes and courses. Later on the model grew and now handles week menus, step-by-step instructions, utensils and tools, and much more.

After building for a short while we realized that Sanity alone probably wouldn't be enough, since this is a paid service with multiple methods of payment, including in-app purchases on iOS and Android. We needed background jobs, custom login flows and to keep a lot of information that didn't fit naturally into Sanity. Of corse it could be stored in Sanity, but it would be unpractical. Consequently we added a GraphQL layer in between and started expanding the surface of the API to handle users, authentication and authorization.

Performance
In the first version we had simple resolvers for the fields, fetching data independently, but when a request to the GraphQL creates a cascade of API-calls to get data for nested properties, it's simply not fast enough.

So the big challenge in the project [related to Sanity] quickly surfaced: how to cache data from Sanity queries efficiently in GraphQL while at the same time avoiding a stale cache.

We ended up solving this by doing two things: caching requests for queries using references (like a category list) with a TTL; and caching all individual objects in the responses by the sanity _id. In the background we use a sanity listener to invalidate lists and individual object in the cache if a change is applied to the document in question in Sanity.

We're in the middle of doing some work now to be able to store the cache in Redis instead of memory and will hopefully be able to open source that part at some point 🤞.

Sanity and other friends
We ended up with a node server running a GraphQL server built with apollo-server and graphql-modules, Mux for video, RevenueCat for in-app purchase handling, Algolia for search and PostMark for transactional email handling.

The chefs started using Sanity pretty much without any training at all, and it's all been very good. Lots of love ❤️

Contributor

Other projects by author

tenk.faktisk.no

School teaching programs for critical media use and source awareness

Kristoffer Brabrand
Go to tenk.faktisk.no

Mikkeller Beer Celebration

Mobile app and website for the Mikkeller Beer Celebration (MBCC) craft beer festival, with user-contributed beer ratings, news and Untappd integration.

Go to Mikkeller Beer Celebration

PåTapp.no

Shows beers currently on tap at craft beer bars in the Norwegian cities of Oslo, Bergen, Sandnes and Stavanger.

Go to PåTapp.no