Web application

Recipes

Full-stack project for storing recipes. Deep dive into Next and Tailwind, I wanted to try out React-Query with built GraphQL API and automatically generated code. For authentication, I used the JSON Web Tokens method.

Overview

A quick look at general information about the project with a brief description of the development process.

Project

The project is a web application to store and review recipes. The goal was to reach a state of a minimum viable product, constructed from many proofs of concepts built around topics I wanted to explore (Next + Tailwind, NextAPI + GraphQL + Apollo + MongoDB + Redis, React-Query, react-hook-form, using Content Management System). With minimalistic deploy on my server.

Project difficulties

On backend everything was as challenging as it was new. From learning ways of debugging server side of an application, through connecting and working with database, maintaining type-safe schema, and deploying whole build to the server.

Solutions

I chose GraphQL API, as I used its syntax with Gatsby. The project was meant to be a typical CRUD app with basic backend functionalities so I went with the NoSql database (MongoDB with Mongoose as ORM) to avoid maintaining relations. I used graphql/codegen for managing type safety between client and server. For fetching and synchronizing state client-server, I chose to explore react-query, started with v4, and migrated to v5.

Notable features

  • GraphQL API built with Apollo server, Type-graphql, MongoDB, and Redis.

  • Authentication using JSON Web Tokens.

  • Persisting state on a server while creating a recipe.

  • Type-safe automatically generated GraphQL queries and mutations.

  • API requests built with react-request and managed by react-query.

  • CRUD operations implemented on a client and a server-side.

  • Dynamic forms with react-hook-form using React Context API.

  • Fully reusable Slider component using React Context API.

  • Form validation with yup. Authentication validation on a server.

  • Image upload with Cloudinary as a Content Management System.

  • Search bar for recipes by title and type of cuisine.

  • Fully responsive, with different mobile and desktop navigation bars.

  • Add reviews to recipes, only if user is not an author of the recipe.

  • App state management with Redux Toolkit.

Tech stack

  • Typescript

  • React

  • Next

  • Tailwind

  • Apollo

  • GraphQL

  • MongoDB

  • Redis

Project goals

Section which trying to answer question: why this project?

  • Client-server CRUD operations

    The main goal was to implement CRUD functionality, firstly very basic, with pure typescript. Connect and maintain state on the server, and integrate it with form libraries like react-hook-form. Lastly focus on performance, in terms of the required number of queries per operation, and how to use GraphQL advantages in that field.

    Client-server CRUD operationsProject goals
  • Authentication using Jason Web Tokens

    Focus on how to store (hash passwords), maintain user sessions with Redis, and create middleware to automatically validate operations based on provided tokens. Lastly, create a form on the client side with server validation of given inputs.

    Authentication using Jason Web TokensProject goals
  • Form libraries

    Todo app with authentication seemed a perfect fit to explore form libraries like formik and react-hook-form. From static components to dynamic inputs used across all the forms. I ended up exploring react-hook-form the most, as it seemed to be more dynamic than formik.

    Form librariesProject goals
  • Tools for testing server requests and database

    Explore Postman for GraphQL queries and mutations or to check cookies, MongoDB Compas to work directly on the database.

    Tools for testing server requests and databaseProject goals

Tech stack decisions

It is a much better developer experience than in Gatsby, well documented, huge, and helpful acolyte base. I wanted to use API routes for the GraphQL endpoint. Different approach to data fetching methods (getServerProps etc.), a bit more flexible.

Just make life a lot easier with CSS, sometimes perfectly discouraging bad practices in terms of UI decisions, because of utility-first approach. Not as dynamic as CSS-in-JS libraries, but adjustable with plain html properties. A true blast.

Simple GraphQL backend seemed a good and intuitive choice for the CRUD app, REST API could be much simpler in terms of implementation, but on the client side, it felt like it saved a lot of unnecessary requests. Probably with react-query, it would not make much of a difference. Just another way of doing things that was fun to explore.

I was thinking about PostgreSQL and even started implementing it. On the level of this application, the differences are very small. I know I am going to use it a lot PostgreSQL with my future projects, so I gave MongoDB a try and did not have any problems with it at any point.

Approach with form logic made with hooks, using Context API seems very well thought out and pretty straightforward, but when complexity comes in, nested components with their own life cycles, things get messy. A couple of workarounds and it is working gracefully. Dynamic inputs are where this library shines.

Approach with form logic made with hooks, using Context API seems very well thought out and pretty straightforward, but when complexity comes in, nested components with their own life cycles, things get messy. A couple of workarounds and it is working gracefully. Dynamic inputs are where this library shines.

Notable features

Auth client-server

On client side validation with zod, managing cookies, automatic user fetching with react-query. On server side managing JWT tokens with redis session.

CRUD operations integrated with using forms

Creating and editing recipes made with react-hook-form combined with zod validation if needed.

Preservation of state client-server

On client side I used redux for storing user info, forms state synchronized with react-query (ex. setQueryData).

GET IN TOUCH

Contact

Want to reach out about a project, collaboration, or just want to say friendly hello?

Message not send