Skip to content

Leveraging GraphQL Scalars to Enhance Your Schema

Leveraging GraphQL Scalars to Enhance Your Schema

Introduction

GraphQL has revolutionized the way developers approach application data and API layers, gaining well-deserved momentum in the tech world. Yet, for all its prowess, there's room for enhancement, especially when it comes to its scalar types. By default, GraphQL offers a limited set of these primitives — Int, Float, String, Boolean, and ID — that underpin every schema. While these types serve most use cases, there are scenarios where they fall short, leading developers to yearn for more specificity in their schemas.

Enter graphql-scalars, a library designed to bridge this gap. By supplementing GraphQL with a richer set of scalar types, this tool allows for greater precision and flexibility in data representation. In this post, we'll unpack the potential of enhanced Scalars, delve into the extended capabilities provided by graphql-scalars, and demonstrate its transformative power using an existing starter project. Prepare to redefine the boundaries of what your GraphQL schema can achieve.

Benefits of Using Scalars

GraphQL hinges on the concept of "types." Scalars, being the foundational units of GraphQL's type system, play a pivotal role. While the default Scalars — Int, Float, String, Boolean, and ID — serve many use cases, there's an evident need for more specialized types in intricate web development scenarios.

  1. Precision: Using default Scalars can sometimes lack specificity. Consider representing a date or time in your application with a String; this might lead to ambiguities in format interpretation and potential inconsistencies.
  2. Validation: Specialized scalar types introduce inherent validation. Instead of using a String for an email or a URL, for example, distinct types ensure the data meets expected formats at the query level itself.
  3. Expressiveness: Advanced Scalars provide clearer intentions. They eliminate ambiguity inherent in generic types, making the schema more transparent and self-explanatory.

Acknowledging the limitations of the default Scalars, tools like graphql-scalars have emerged. By broadening the range of available data types, graphql-scalars allows developers to describe their data with greater precision and nuance.

Demonstrating Scalars in Action with Our Starter Project

To truly grasp the transformative power of enhanced Scalars, seeing them in action is pivotal. For this, we'll leverage a popular starter kit: the Serverless framework with Apollo and Contentful. This kit elegantly blends the efficiency of serverless functions with the power of Apollo's GraphQL and Contentful's content management capabilities.

Setting Up the Starter:

  1. Initialize the Project:
npm create @this-dot/starter -- --kit serverless-framework-apollo-contentful
  1. When prompted, name your project enhance-with-graphql-scalars.
Welcome to starter.dev! (create-starter)
✔ What is the name of your project? … enhance-with-graphql-scalars
> Downloading starter kit...
✔ Done!

Next steps:
 cd enhance-with-graphql-scalars
 npm install (or pnpm install, yarn, etc)
  1. For a detailed setup, including integrating with Contentful and deploying your serverless functions, please follow the comprehensive guide provided in the starter kit here.
  2. And we add the graphql-scalars package
npm install graphql-scalars

Enhancing with graphql-scalars:

Dive into the technology.typedefs.ts file, which is the beating heart of our GraphQL type definitions for the project. Initially, these are the definitions we encounter:

export const technologyTypeDefs = gql`
	type Technology {
		id: ID!
		displayName: String!
		description: String
		url: URL
	}

	type Query {
		"Technology: GET"
		technology(id: ID!): Technology
		technologies(offset: Int, limit: Int): [Technology!]
	}

	type Mutation {
		"Technology: create, read and delete operations"
		createTechnology(displayName: String!, description: String, url: String): Technology
		updateTechnology(id: ID!, fields: TechnologyUpdateFields): Technology
		deleteTechnology(id: ID!): ID
	}

	input TechnologyUpdateFields {
		"Mutable fields of a technology entity"
		displayName: String
		description: String
		url: String
	}
`;

Our enhancement strategy is straightforward:

  • Convert the url field from a String to the URL scalar type, bolstering field validation to adhere strictly to the URL format.

Post-integration of graphql-scalars, and with our adjustments, the revised type definition emerges as:

export const technologyTypeDefs = gql`
	type Technology {
		id: ID!
		displayName: String!
		description: String
		url: URL
	}

	type Query {
		"Technology: GET"
		technology(id: ID!): Technology
		technologies(offset: Int, limit: Int): [Technology!]
	}

	type Mutation {
		"Technology: create, read and delete operations"
		createTechnology(displayName: String!, description: String, url: URL): Technology
		updateTechnology(id: ID!, fields: TechnologyUpdateFields): Technology
		deleteTechnology(id: ID!): ID
	}

	input TechnologyUpdateFields {
		"Mutable fields of a technology entity"
		displayName: String
		description: String
		url: URL
	}
`;

To cap it off, we integrate the URL type definition along with its resolvers (sourced from graphql-scalars) in the schema/index.ts file:

import { mergeResolvers, mergeTypeDefs } from '@graphql-tools/merge';
import { technologyResolvers, technologyTypeDefs } from './technology';
import { URLResolver, URLTypeDefinition } from 'graphql-scalars';

const graphqlScalars = [URLTypeDefinition];

export const typeDefs = mergeTypeDefs([...graphqlScalars, technologyTypeDefs]);

export const resolvers = mergeResolvers([{ URL: URLResolver }, technologyResolvers]);

This facelift doesn't just refine our GraphQL schema but infuses it with innate validation, acting as a beacon for consistent and accurate data.

Testing in the GraphQL Sandbox

Time to witness our changes in action within the GraphQL sandbox. Ensure your local server is humming along nicely.

Kick off with verifying the list query:

query {
  technologies {
    id
    displayName
    url
  },
}

Output:

{
  "data": {
    "technologies": [
      {
        "id": "4UXuIqJt75kcaB6idLMz3f",
        "displayName": "GraphQL",
        "url": "https://graphql.framework.dev/"
      },
      {
        "id": "5nOshyir74EmqY4Jtuqk2L",
        "displayName": "Node.js",
        "url": "https://nodejs.framework.dev/"
      },
      {
        "id": "5obCOaxbJql6YBeXmnlb5n",
        "displayName": "Express",
        "url": "https://www.npmjs.com/package/express"
      }
    ]
  }
}

Success! Each url in our dataset adheres to the pristine URL format. Any deviation would've slapped us with a format error.

Now, let's court danger. Attempt to update the url field with a wonky format:

mutation {
  updateTechnology(id: "4UXuIqJt75kcaB6idLMz3f", fields: { url: "aFakeURLThatShouldThrowError" }) {
    id
    displayName
    url
  }
}

As anticipated, the API throws up a validation roadblock:

{
  "data": {},
  "errors": [
    {
      "message": "Expected value of type \"URL\", found \"aFakeURLThatShouldThrowError\"; Invalid URL",
      "locations": [
        {
          "line": 18,
          "column": 65
        }
      ],
      "extensions": {
        "code": "GRAPHQL_VALIDATION_FAILED",
        "stacktrace": [
          "TypeError [ERR_INVALID_URL]: Invalid URL",
          "    at new NodeError (node:internal/errors:399:5)",
          "    at new URL (node:internal/url:560:13)",
          ...
        ]
      }
    }
  ]
}

For the final act, re-run the initial query to reassure ourselves that the original dataset remains untarnished.

Conclusion

Enhancing your GraphQL schemas with custom scalars not only amplifies the robustness of your data structures but also streamlines validation and transformation processes. By setting foundational standards at the schema level, we ensure error-free, consistent, and meaningful data exchanges right from the start.

The graphql-scalars library offers an array of scalars that address common challenges developers face. Beyond the URL scalar we explored, consider diving into other commonly used scalars such as:

  • DateTime: Represents date and time in the ISO 8601 format.
  • Email: Validates strings as email addresses.
  • PositiveInt: Ensures integer values are positive.
  • NonNegativeFloat: Guarantees float values are non-negative.

As a potential next step, consider crafting your own custom scalars tailored to your project's specific requirements. Building a custom scalar not only offers unparalleled flexibility but also provides deeper insights into GraphQL's inner workings and its extensibility.

Remember, while GraphQL is inherently powerful, the granular enhancements like scalars truly elevate the data-fetching experience for developers and users alike. Always evaluate your project's needs and lean into enhancements that bring the most value.

To richer and more intuitive GraphQL schemas!

This Dot Labs is a development consultancy that is trusted by top industry companies, including Stripe, Xero, Wikimedia, Docusign, and Twilio. This Dot takes a hands-on approach by providing tailored development strategies to help you approach your most pressing challenges with clarity and confidence. Whether it's bridging the gap between business and technology or modernizing legacy systems, you’ll find a breadth of experience and knowledge you need. Check out how This Dot Labs can empower your tech journey.

You might also like

How to Create a GraphQL Rest API Wrapper and Enhance Your Data cover image

How to Create a GraphQL Rest API Wrapper and Enhance Your Data

Intro Today we will talk about wrapping a REST API with a GraphQL wrapper, which means that the REST API will be accessible via a different GraphQL API. We’ll be using Apollo Server for the implementation. This article assumes you have a basic understanding of REST API endpoints, and some knowledge of GraphQL. Here is the code repo if you want to review it while reading. With that said, we will be looking at why you would wrap a REST API, how to wrap an existing REST API, and how you can enhance your data using GraphQL. Why wrap a REST API with GraphQL There are a couple of different reasons to wrap a REST API. The first is migrating from an existing REST API, which you can learn about in detail here, and the second is creating a better wrapper for existing data. Granted, this can be done using REST. But for this article, we will focus on a GraphQL version. A reason for creating a better wrapper would be using a CMS that provides custom fields. For instance, you get a field that is listed as C435251, and it has a value of 532. This doesn’t mean anything to us. But when looking at the CMS these values could indicate something like “Breakfast Reservation” is set to “No”. So, with our wrapping, we can return it to a more readable value. Another example is connecting related types. For instance, in the code repo for this blog, we have a type Person with a connection to the type Planet. __Connection example__* ` type Person { """The name of this person.""" name: String """A planet that this person was born on or inhabits.""" homeworld: Planet } type Planet { """The name of this planet.""" name: String } ` How to Wrap a REST API Alright, you have your REST API, and you might wonder how to wrap it with GraphQL? First, you will call your REST API endpoint, which is inside your rest-api-sources file inside your StarwarsAPI class. __REST API example__* ` class StarwarsAPI { constructor() { this.axios = axios.create({ baseURL: 'https://swapi.dev/api/', }); } async getPerson(id) { const { data } = await this.axios.get(people/${id}`); return data } async getHomeworld(id) { const { data } = await this.axios.get(planets/${id}`); return data } } ` This above class will then be imported and used in the server/index file to set up your new Apollo server. __Apollo server example__* ` const StarwarsAPI = require('./rest-api-sources/starwars-rest-api'); const server = new ApolloServer({ typeDefs, resolvers, dataSources: () => ({}), context: () => { return { starwarsAPI: new StarwarsAPI(), }; }, }); ` Now, in your GraphQL resolver, you will make a person query and retrieve your starWarsAPI from it, which contains the information you want to call. __GraphQL resolver__* ` const resolvers = { Query: { person: async (, { id }, { starwarsAPI }) => { return await starwarsAPI.getPerson(id); }, }, }; ` With the above done, let's start on how to enhance your data in the resolver. Enhancing your data With our resolver up and running, we’ll now use it to enhance some of our data. For now, we’ll make the name we get back returned in a first name, and the last initial format. To do so above our Query, we’ll start a Person object and put the variable name inside it. We’ll then grab the name from our Query and proceed to tweak it into the format we want. __Enhancing in resolver__* ` Person: { name: ({ name }) => { if (!name) { return null; } const [first, last] = name.split(" ") if (last === undefined) { return first } return ${first} ${last[0].toUpperCase()}.` } }, ` Tada! Now, when we call our GraphQL, our name will return formatted in a first name, and last initial state. Conclusion Today's article covered why you want to wrap a REST API with GraphQL for migration or to provide a better API layer, how to wrap an existing REST API with GraphQL, and how you can use the resolver to enhance your data for things like name formatting. I hope it was helpful, and will give others a good starting point. If you want to learn more about GraphQL and REST API wrappers, read up on our resources available at graphql.framework.dev....

Introducing the New Serverless, GraphQL, Apollo Server, and Contentful Starter kit cover image

Introducing the New Serverless, GraphQL, Apollo Server, and Contentful Starter kit

Introducing the new Serverless, GraphQL, Apollo Server, and Contentful Starter kit The team at This Dot Labs has released a brand new starter kit which includes the Serverless Framework, GraphQL, Apollo Server and Contentful configured and ready to go. This article will walk through how to set up the new kit, the key technologies used, and reasons why you would consider using this kit. Table of Contents - How to get started setting up the kit - Generate the project - Setup Contentful access - Setting up Docker - Starting the local server - How to Create the Technology Model in Contentful - How to seed the database with demo data - How to work with the migration scripts - Technologies included in this starter kit - Why use GraphQL? - Why use Contentful? - Why use Amazon Simple Queue Service (SQS)? - Why use Apollo Server? - Why use the Serverless Framework? - Why use Redis? - Why use the Jest testing framework? - Project structure - How to deploy your application - What can this starter kit be used for? - Conclusion How to get started setting up the kit Generate the project In the command line, you will need to start the starter.dev CLI by running the npx @this-dot/create-starter` command. You can then select the `Serverless Framework, Apollo Server, and Contentful CMS` kit and name your new project. Then you will need to `cd` into your new project directory and install the dependencies using the tool of your choice (npm, yarn, or pnpm). Next, you will need to Run `cp .env.example .env` to copy the contents of the `.env.example` file into the `.env` file. Setup Contentful access You will first need to create an account on Contentful, if you don't have one already. Once you are logged in, you will need to create a new space. From there, go to Settings -> API keys` and click on the `Content Management Tokens` tab. Next, click on the `Generate personal token` button and give your token a name. Copy your new Personal Access Token, and add it to the `CONTENTFUL_CONTENT_MANAGEMENT_API_TOKEN` variable. Then, go to `Settings -> General settings` to get the `CONTENTFUL_SPACE_ID`. The last step is to add those `CONTENTFUL_CONTENT_MANAGEMENT_API_TOKEN` and `CONTENTFUL_SPACE_ID` values to your `.env` file. Setting up Docker You will first need to install Docker Desktop if you don't have it installed already. Once installed, you can start up the Docker container with the npm run infrastructure:up` command. Starting the local server While the Docker container is running, open up a new tab in the terminal and run npm run dev` to start the development server. Open your browser to `http://localhost:3000/dev/graphql` to open up Apollo server. How to Create the Technology Model in Contentful To get started with the example model, you will first need to create the model in Contentful. 1. Log into your Contentful account 2. Click on the Content Model` tab 3. Click on the Design your Content Modal` button if this is your first modal 4. Create a new model called Technology` 5. Add three new text fields called displayName`, `description` and `url` 6. Save your new model How to seed the database with demo data This starter kit comes with a seeding script that pre-populates data for the Technology` Content type. In the command line, run npm run db:seed` which will add three new data entries into Contentful. If you want to see the results from seeding the database, you can execute a small GraphQL query using Apollo server. First, make sure Docker, and the local server(npm run dev`) are running, and then navigate to `http://localhost:3000/dev/graphql`. Add the following query: ` query TechnologyQuery { technologies { description displayName url } } ` When you run the query, you should see the following output. `json { "data": { "technologies": [ { "description": "GraphQL provides a strong-typing system to better understand and utilize our API to retrieve and interact with our data.", "displayName": "GraphQL", "url": "https://graphql.framework.dev/" }, { "description": "Node.js® is an open-source, cross-platform JavaScript runtime environment.", "displayName": "Node.js", "url": "https://nodejs.framework.dev/" }, { "description": "Express is a minimal and flexible Node.js web application framework.", "displayName": "Express", "url": "https://www.npmjs.com/package/express" } ] } } ` How to work with the migration scripts Migrations are a way to make changes to your content models and entries. This starter kit comes with a couple of migration scripts that you can study and run to make changes to the demo Technology` model. These migration scripts are located in the `scripts/migration` directory. To get started, you will need to first install the contentful-cli`. `sh npm i -g contentful-cli ` You can then login to Contentful using the contentful-cli`. `sh contentful login ` You will then need to choose the Contentful space where the Technology` model is located. `sh contentful space use ` If you want to modify the existing demo content type, you can run the second migration script from the starter kit. `sh contentful space migration scripts/migrations/02-edit-technology-contentType.js -y ` If you want to build out more content models using the CLI, you can study the example code in the /scripts/migrations/01-create-technology-contentType.js` file. From there, you can create a new migration file, and run the above `contentful space migration` command. If you want to learn more about migration in Contentful, then please check out the documentation. Technologies included in this starter kit Why use GraphQL? GraphQL is a query language for your API and it makes it easy to query all of the data you need in a single request. This starter kit uses GraphQL to query the data from our Contentful` space. Why use Contentful? Contentful is a headless CMS that makes it easy to create and manage structured data. We have integrated Contentful into this starter kit to make it easy for you to create new entries in the database. Why use Amazon Simple Queue Service (SQS)? Amazon Simple Queue Service (SQS) is a queuing service that allows you to decouple your components and process and store messages in a scalable way. In this starter kit, an SQS message is sent by the APIGatewayProxyHandler` using the `sendMessage` function, which is then stored in a queue called `DemoJobQueue`. The SQS handler `sqs-handler` polls this queue, and processes any message received. `ts import { APIGatewayProxyHandler } from "aws-lambda"; import { sendMessage } from "../utils/sqs"; export const handler: APIGatewayProxyHandler = async (event) => { const body = JSON.parse(event.body || "{}"); const resp = await sendMessage({ id: Math.ceil(Math.random() 100), message: body.message, }); return { statusCode: resp.success ? 200 : 400, body: JSON.stringify(resp.data), }; }; ` Why use Apollo Server? Apollo Server is a production-ready GraphQL server that works with any GraphQL client, and data source. When you run npm run dev` and open the browser to `http://localhost:3000/dev/graphql`, you will be able to start querying your Contentful data in no time. Why use the Serverless Framework? The Serverless Framework is used to help auto-scale your application by using AWS Lambda functions. In the starter kit, you will find a serverless.yml` file, which acts as a configuration for the CLI and allows you to deploy your code to your chosen provider. This starter kit also includes the following plugins: - serverless-offline` - allows us to deploy our application locally to speed up development cycles. - serverless-plugin-typescript` - allows the use of TypeScript with zero-config. - serverless-dotenv-plugin` - preloads function environment variables into the Serverless Framework. Why use Redis? Redis is an open-source in-memory data store that stores data in the server memory. This starter kit uses Redis to cache the data to reduce the API response times and rate limiting. When you make a new request, those new requests will be retrieved from the Redis cache. Why use the Jest testing framework? Jest is a popular testing framework that works well for creating unit tests. You can see some example test files under the src/schema/technology` directory. You can use the `npm run test` command to run all of the tests. Project structure Inside the src` directory, you will find the following structure: ` . ├── generated │ └── graphql.ts ├── handlers │ ├── graphql.ts │ ├── healthcheck.spec.ts │ ├── healthcheck.ts │ ├── sqs-generate-job.spec.ts │ ├── sqs-generate-job.ts │ ├── sqs-handler.spec.ts │ └── sqs-handler.ts ├── models │ └── Technology │ ├── create.spec.ts │ ├── create.ts │ ├── getAll.spec.ts │ ├── getAll.ts │ ├── getById.spec.ts │ ├── getById.ts │ ├── index.ts │ ├── TechnologyModel.spec.ts │ └── TechnologyModel.ts ├── schema │ ├── technology │ │ ├── index.ts │ │ ├── technology.resolver.spec.ts │ │ ├── technology.resolvers.ts │ │ └── technology.typedefs.ts │ └── index.ts └── utils ├── contentful │ ├── contentful-healthcheck.spec.ts │ ├── contentful-healthcheck.ts │ ├── contentful.spec.ts │ ├── contentful.ts │ └── index.ts ├── redis │ ├── index.ts │ ├── redis-healthcheck.spec.ts │ ├── redis-healthcheck.ts │ ├── redis.spec.ts │ └── redis.ts ├── sqs │ ├── client.spec.ts │ ├── client.ts │ ├── getQueueUrl.spec.ts │ ├── getQueueUrl.ts │ ├── index.ts │ ├── is-offline.spec.ts │ ├── is-offline.ts │ ├── sendMessage.spec.ts │ └── sendMessage.ts └── test └── mocks ├── contentful │ ├── entry.ts │ └── index.ts ├── aws-lambda-handler-context.ts ├── graphql.ts ├── index.ts └── sqs-record.ts ` This given structure makes it easy to find all of the code and tests related to that specific component. This structure also follows the single responsibility principle which means that each file has a single purpose. How to deploy your application The Serverless Framework needs access to your cloud provider account so that it can create and manage resources on your behalf. You can follow the guide to get started. Steps to get started: 1. Sign up for an AWS account 2. Create an IAM User and Access Key 3. Export your AWS_ACCESS_KEY_ID` & `AWS_SECRET_ACCESS_KEY` credentials. `sh export AWSACCESS_KEY_ID= export AWSSECRET_ACCESS_KEY= ` 4. Deploy your application on AWS Lambda`: `sh npm run deploy ` 5. To deploy a single function, run: `sh npm run deploy function --function myFunction ` To stop your Serverless application, run: `sh serverless remove ` For more information on Serverless deployment, check out this article. What can this starter kit be used for? This starter kit is very versatile, and can be used with a front-end application for a variety of situations. Here are some examples: - personal developer blog - small e-commerce application Conclusion In this article, we looked at how we can get started using the Serverless, GraphQL, Apollo Server, and Contentful Starter kit. We also looked at the different technologies used in the kit, and why they were chosen. Lastly, we looked at how to deploy our application using AWS. I hope you enjoy working with our new starter kit!...

Follow These Best Practices for Using Git cover image

Follow These Best Practices for Using Git

As a developer, working in a version control system is a basic necessity as soon as you start any project. The 2021 Technology Survey by Stack Overflow shows Git as the most popular technology tool, reinforcing how important it is to understand, and use it correctly, in your projects. This article compiles some tips and hopefully good advice when working with Git. Never push to the main branch. > "The Git feature that really makes it stand apart from nearly every other SCM out there is its branching model." - from git-scm Pushing directly to the main branch doesn't make much sense in Git as it doesn't promote collaboration. Instead, make use of merges/rebases from pull requests** that most providers have (GitHub, AWS CodeCommit, etc.). Define patterns & standards within your team Every team has its patterns and standards for naming conventions, tags, and commit messages. Those should be followed and pointed out in all pull-request reviews. If you don't have any starting pattern, here are a couple of suggestions: - branch name**: `user_name/ticket_number,-short_description_dashed` - example: mimurawil/1,-my-first-commit` - commit title**: `type(scope): short_description` - type: feat, fix, revert, etc - scope: ticket number (can be prefixed by "#") - example: fix(#1): fix broken build` Write useful commit messages Try to focus more on "why" and "what" instead of "how". You are spending a bit more time to complete your commit, but it will pay back when your future self or teammates revisit that piece of code. ` fix(#42): use proper url prefix on social share images During build time, our pages don't know or don't have access to the location` props, making the prefix for our image URL's to be `undefined`. Fixing this by using the proper SITE_URL` from our env variables. ref: ticket #42 link ` Rebase your branch frequently Rebasing your branch frequently ensures you are always working with the latest version from the main branch. Your teammates will review the correct changes, and you will usually encounter no conflicts when merging to the main branch. ` -i for interactive rebase git rebase -i main ` (make sure you have your local main branch updated from remote)_ Make use of Git commands A few Git commands that I found incredibly useful in my journey: - git revert`: creates a new commit that reverts changes from a specific commit - git stash`: stores the changes and goes back to a clean working directory - git cherry-pick`: picks one specific commit and adds it on top of your current branch - git bisect`: help you find a specific commit in the history that added a bug in your codebase...

I Broke My Hand So You Don't Have To (First-Hand Accessibility Insights) cover image

I Broke My Hand So You Don't Have To (First-Hand Accessibility Insights)

We take accessibility quite seriously here at This Dot because we know it's important. Still, throughout my career, I've seen many projects where accessibility was brushed aside for reasons like "our users don't really use keyboard shortcuts" or "we need to ship fast; we can add accessibility later." The truth is, that "later" often means "never." And it turns out, anyone could break their hand, like I did. I broke my dominant hand and spent four weeks in a cast, effectively rendering it useless and forcing me to work left-handed. I must thus apologize for the misleading title; this post should more accurately be dubbed "second-hand" accessibility insights. The Perspective of a Developer Firstly, it's not the end of the world. I adapted quickly to my temporary disability, which was, for the most part, a minor inconvenience. I had to type with one hand, obviously slower than my usual pace, but isn't a significant part of a software engineer's work focused on thinking? Here's what I did and learned: - I moved my mouse to the left and started using it with my left hand. I adapted quickly, but the experience wasn't as smooth as using my right hand. I could perform most tasks, but I needed to be more careful and precise. - Many actions require holding a key while pressing a mouse button (e.g., visiting links from the IDE), which is hard to do with one hand. - This led me to explore trackpad options. Apart from the Apple Magic Trackpad, choices were limited. As a Windows user (I know, sorry), that wasn't an option for me. I settled for a cheap trackpad from Amazon. A lot of tasks became easier; however, the trackpad eventually malfunctioned, sending me back to the mouse. - I don't know a lot of IDE shortcuts. I realized how much I've been relying on a mouse for my work, subconsciously refusing to learn new keyboard shortcuts (I'll be returning my senior engineer license shortly). So I learned a few new ones, which is good, I guess. - Some keyboard shortcuts are hard to press with one hand. If you find yourself in a similar situation, you may need to remap some of them. - Copilot became my best friend, saving me from a lot of slow typing, although I did have to correct and rewrite many of its suggestions. The Perspective of a User As a developer, I was able to get by and figure things out to be able to work effectively. As a user, however, I got to experience the other side of the coin and really feel the accessibility (or lack thereof) on the web. Here are a few insights I gained: - A lot of websites apparently tried_ to implement keyboard navigation, but failed miserably. For example, a big e-commerce website I tried to use to shop for the aforementioned trackpad seemed to work fine with keyboard navigation at first, but once I focused on the search field, I found myself unable to tab out from it. When you make the effort to implement keyboard navigation, please make sure it works properly and it doesn't get broken with new changes. I wholeheartedly recommend having e2e tests (e.g. with Playwright) that verify the keyboard navigation works as expected. - A few websites and web apps I tried to use were completely unusable with the keyboard and were designed to be used with a mouse only. - Some sites had elaborate keyboard navigation, with custom keyboard shortcuts for different functionality. That took some time to figure out, and I reckon it's not as intuitive as the designers thought it would be. Once a user learns the shortcuts, however, it could make their life easier, I suppose. - A lot of interactive elements are much smaller than they should be, making it hard to accurately click on them with your weaker hand. Designers, I beg you, please make your buttons bigger. I once worked on an application that had a "gloves mode" for environments where the operators would be using gloves, and I feel like maybe the size we went with for the "gloves mode" should be the standard everywhere, especially as screens get bigger and bigger. - Misclicking is easy, especially using your weaker hand. Be it a mouse click or just hitting an Enter key on accident. Kudos to all the developers who thought about this and implemented a confirmation dialog or other safety measures to prevent users from accidentally deleting or posting something. I've however encountered a few apps that didn't have any of these, and those made me a bit anxious, to be honest. If this is something you haven't thought about when developing an app, please start doing so, you might save someone a lot of trouble. Some Second-Hand Insights I was only a little bit impaired by being temporarily one-handed and it was honestly a big pain. In this post, I've focused on my anecdotal experience as a developer and a user, covering mostly keyboard navigation and mouse usage. I can only imagine how frustrating it must be for visually impaired users, or users with other disabilities, to use the web. I must confess I haven't always been treating accessibility as a priority, but I've certainly learned my lesson. I will try to make sure all the apps I work on are accessible and inclusive, and I will try to test not only the keyboard navigation, ARIA attributes, and other accessibility features, but also the overall experience of using the app with a screen reader. I hope this post will at least plant a little seed in your head that makes you think about what it feels like to be disabled and what would the experience of a disabled person be like using the app you're working on. Conclusion: The Humbling Realities of Accessibility The past few weeks have been an eye-opening journey for me into the world of accessibility, exposing its importance not just in theory but in palpable, daily experiences. My short-term impairment allowed me to peek into a life where simple tasks aren't so simple, and convenient shortcuts are a maze of complications. It has been a humbling experience, but also an illuminating one. As developers and designers, we often get caught in the rush to innovate and to ship, leaving behind essential elements that make technology inclusive and humane. While my temporary disability was an inconvenience, it's permanent for many others. A broken hand made me realize how broken our approach towards accessibility often is. The key takeaway here isn't just a list of accessibility tips; it's an earnest appeal to empathize with your end-users. "Designing for all" is not a checkbox to tick off before a product launch; it's an ongoing commitment to the understanding that everyone interacts with technology differently. When being empathetic and sincerely thinking about accessibility, you never know whose life you could be making easier. After all, disability isn't a special condition; it's a part of the human condition. And if you still think "Our users don't really use keyboard shortcuts" or "We can add accessibility later," remember that you're not just failing a compliance checklist, you're failing real people....