Chris Padilla/Blog

My passion project! Posts spanning music, art, software, books, and more
You can follow by Newsletter or RSS! (What's RSS?) Full archive here.

    Collocation in React Server Components

    At work, we're starting to spin up a Next.js app and are using the new server components! I'll share a quick look at a simple example of what it looks like and why this is a return to form for website building on the web.

    A Brief History of Templating

    The pendulum of web development needs and trends have swung back and forth between two sides: Heavy lifting on the client, and on the server. When thinking about an application that uses dynamic content (forums, user account sites, wikis), the major glueing that needs to happen is between data and templates. Somewhere, you have to populate a template with the requested data based on the page.

    Historically, web servers handled this with templating frameworks. Popular Express templating engines include Pug and Handlebars, in C# the ASP.NET framework uses Razor pages.

    A popular design pattern for these types of servers was the Model-View-Controller approach. Essentially, separating file functions based on the roles they played.

    When React gained popularity, it was for it's... well, Reactivity. By handling templating on the client, smaller components were able to respond dynamically, eliminating the need for an entire page refresh.

    Web performance standards, driven largely by Google's own SEO rankings of pages, have since reigned in the excessive use of client side code for public facing web pages.

    And so, the pendulum is swinging back, and the React framework has taken an official stance on how to solve the issue within their own API.

    By acting as a templating engine on the server, the amount of js shipped to the client majorly shrinks, allowing for faster page loads with a lighter footprint on the client. All the while, React still structures this in such a way that you can maintain some of the best features of using the JS framework, including component reactivity and page hydration.

    Server Components

    Examples here will come from Next.js, which at this time is required to have access to this new feature.

    By default, all components are marked as server components. A server component for a page may look like this:

    import React from 'react';
    import db from 'lib/db';
    import {getServerSession} from 'next-auth';
    import authOptions from '@api/auth/[...nextauth]/authOptions';
    import ClientSignIn from './ClientSignIn';
    
    const PageBody = async () => {
        const session = await getServerSession(authOptions);
    
        return (
            <div className="m-20">
                Hello {session.name}!
                <br />
                <ClientSignIn session={session} />
            </div>
        );
    };
    
    export default PageBody;

    You can read the functional component linearly as you would a vanilla js function. We're essentially writing a script saying "get the session, await the response, then render my page."

    In this simple example is one of the larger paradigm shifts as well as the power of the new feature.

    Were I to write this on a client component, I would have to write a useEffect that fetched my session data, I would have to expose an API on my server, write the logic on the server to get the session data, and store the data in my client side state, and then finally render my data. Except, additionally, I would have to manage loading state on the client – showing a skeleton loader or a spinner, and then rending the page when the data has loaded. Phew!

    Here, we've skipped several of those steps by directly accessing the database and returning the result in our JSX. If I needed to, I could massage the data within the component as well, work that otherwise would have required a separate API to handle or would need to be done on the client.

    Colocation

    The main paradigm shift here is colocation in favor of separation of concerns. The first time writing a db query in a React component is a jarring moment! But, colocation is a trend we've seen in motion even with CSS in JS libraries. This furthers it by having all server related code and templating code in one react server component.

    For complex apps, this colocation can be a nice DX improvement, with all the relevant business logic not far from the template. All the while, the option for abstraction and decoupling is still available.

    Many more thoughts on this, but I'll leave it there for today!

    April In Paris

    Listen on Youtube

    I never knew the charm of spring~ Never met it face to face 🎵

    Louie and Ella have my favorite rendition.

    Kermit!

    🐸

    Watching the Muppets Show. Never knew that Dizzy Gillespie was a guest star on an episode!

    JWTs and Database Sessions from an Architecture Standpoint

    This week: A quick look at two session persistence strategies, JWT's and Database storage.

    I'm taking a break from the specific implementation details of OAuth login and credentials sign in with Next Auth. Today, a broader, more widely applicable topic.

    Remember Me

    In the posts linked above, we looked at how to verify a user's identity. Once we've done that, how do we keep them logged in between opening and closing their browser tab?

    There are different ways to manage the specifics of these approaches, but I'll be referencing how it's handled in Next Auth since that's where my head has been!

    With that in mind, the two that are todays topic are storing authentication status in a JWT or storing session data on the Database.

    Database

    More conventional in a standalone application, database sessions will sign the user in, store details about their session on the database, and store a session id in a cookie. That cookie is then sent between the server and client for free with every request without any additional logic written by the client or server side code.

    Once the user has stored the cookie in their browser, they have the session id for each page request across tabs and windows. With each request, the server will verify the session by looking up the record in the database. Any changes made to the user (permissions, signing out) are handled on the db.

    The pros:

    • Centralized source of truth for session data.
    • Seamless update when user role or permissions change.
    • Light on application logic needing to be written on the client.
    • Easy management: can clear session in the event of logging out on all devices or a suspended account.

    The cons:

    • Limited in a distributed system. All session checks must go through the main site and db.
    • Storage costs: db usage scales with active users.
    • DB access costs: requires a roundtrip to DB for every request just to verify session.
    • A DB breach means this information is compromised.

    JWT

    The JWT can be implemented in a similar way: Cookies can be used to transport the identifier. However, the difference here is that session data is stored in the Jason Web Token, with no database backing the session. Instead, an encrypted token along with a unique secret with hashing can be used to verify that a token is signed by your application's server.

    So, instead of database lookups with a session id, your application's secret is used to verify that this is a token administered by your application.

    The pros:

    • Has potential to be a "stateless" login mechanism, allowing for light overhead.
    • Lower DB and access cost.
    • In a distributed system, so long as you verify the secret, it's possible to verify the user across a cloud infrastructure.

    The cons:

    • Added app infrastructure needs to be written to handle token expiration, refreshing, etc.
    • Should the token be compromised, extra steps need to be taken to invalidate the user.
    • A popular approach is to include user permissions with the token. If that's the case, there needs to be logic written to handle the case where there is an update and the token needs re-encoding

    Conclusion

    The cons for JWT are mostly added architecture, while the cons of the database are storage and db request related. If using a distributed, highly scaled system: JWT's lend several strengths to mitigate the cost of complex systems interacting together as well as a high volume of data. For more stand alone applications, however, perhaps the added overhead of managing a JWT strategy is outweighed by the benefits of a simple DB strategy

    PS

    I just realized I've written on this exact subject before! D'oh!

    In The Gist on Authentication, I wrote about authentication methods from a security standpoint, highlighting best practices to avoid XSRF attacks.

    Well, over a year later, I'm thinking more here about performance and scalability. So this one's a keeper. If playing the blues has taught me anything, it's that we're all just riffin' on three chords, anyway!

    New Album — Space Frog 64 🐸

    Pew pew!

    Video Game inspired Drum and Bass! Influenced by Soichi Terada and Jun Chikuma.

    Space Cowboy Forrest Frog pilots his galaxy F-5 aircraft in search of the Hyper Fragment — a now rare material used to power warp speed travel. A group called the Black Hole Herons has aggressively taken control over the mines in the Lake Lenticular Galaxy, and there's only one gunman for the job!

    Purchase on 🤘 Bandcamp and listen on 🙉 Spotify or any of your favorite streaming services!