{"id":47,"date":"2024-12-26T21:00:00","date_gmt":"2024-12-26T21:00:00","guid":{"rendered":"https:\/\/blog.chessboardmagic.com\/?p=47"},"modified":"2025-09-28T21:48:07","modified_gmt":"2025-09-28T21:48:07","slug":"chess-web-programming-part-seven-lichess-api","status":"publish","type":"post","link":"https:\/\/blog.chessboardmagic.com\/index.php\/2024\/12\/26\/chess-web-programming-part-seven-lichess-api\/","title":{"rendered":"Chess Web Programming: Part Seven: Lichess API"},"content":{"rendered":"\n<p><strong>Working with the Lichess API<\/strong><\/p>\n\n\n\n<p>My journey into programming chess applications started with&nbsp;<strong><a href=\"https:\/\/chessboardmagic.com\/\">Chessboard Magic<\/a><\/strong>, a personal project that turned into a platform with over 34 unique chess-based applications. This blog continues my Chess Web Programming series, diving into one of the most exciting aspects of modern development: working with APIs. In this installment, we\u2019ll explore the Lichess API, learn how to interact with it, and create a React application to fetch and display Games from any Lichess User in a structured and beginner-friendly way.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#recap-of-the-previous-parts\"><\/a>Recap of the Previous Parts<\/h4>\n\n\n\n<p>Before we dive into the Lichess API, here&#8217;s a quick recap of the earlier blogs in the series:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-one-getting-started\/8ZKpwJU8\">Getting Started<\/a><\/strong>: Using\u00a0<code>react-chessboard<\/code>\u00a0and\u00a0<code>chess.js<\/code>\u00a0to set up a functional chessboard.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-two-stockfish\/PdeOTODf\">Integrating Stockfish<\/a><\/strong>: Enhancing the application by suggesting the best move using Stockfish.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-three-deploying-your-application\/J3GdsKZP\">Deploying Your Application<\/a><\/strong>: A guide to hosting your chess application online.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-four-chessboard-customisation\/Is0jxElj\">Customizing the Chessboard<\/a><\/strong>: Styling and implementing features like custom piece sets and square highlighting.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-five-game-review\/32JsEsrs\">Game Review<\/a><\/strong>: Adding features like move highlighting and navigation for game analysis.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-six-essential-resources\/Yg5HxCt6\">Essential Resources<\/a><\/strong>: Tools, libraries, and learning materials to support chess application development.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong>&nbsp;This blog assumes that you\u2019ve followed the previous parts of the series, particularly&nbsp;<strong>Blog 1<\/strong>, which covers setting up the foundational tools and concepts. You should already have the necessary software installed (e.g., Node.js, Visual Studio Code) and a basic understanding of React web programming. If you haven\u2019t reviewed Blog 1 yet, we recommend starting there to ensure you\u2019re set up for success.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#what-are-apis\"><\/a>What Are APIs?<\/h2>\n\n\n\n<p>APIs (Application Programming Interfaces) act as intermediaries that allow software applications to communicate with one another. They provide a set of rules and protocols for accessing a service or application&#8217;s features or data. For example, when you check the weather on your phone, the app fetches the data from a server using APIs. Similarly, we\u2019ll use the Lichess API to retrieve chess game data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#what-is-a-restful-api\"><\/a><strong>What Is a RESTful API?<\/strong><\/h4>\n\n\n\n<p>A RESTful API (Representational State Transfer API) is a type of API that adheres to specific architectural principles. It uses standard HTTP methods such as&nbsp;<code>GET<\/code>,&nbsp;<code>POST<\/code>,&nbsp;<code>PUT<\/code>, and&nbsp;<code>DELETE<\/code>&nbsp;to manage resources (like game data or user profiles).<br>RESTful APIs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Are stateless, meaning every request from the client to the server must contain all the information needed to process the request.<\/li>\n\n\n\n<li>Use endpoints (specific URLs) to access different resources.<\/li>\n<\/ul>\n\n\n\n<p>For instance, the Lichess API uses endpoints to provide access to specific types of data. Here&#8217;s an example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Endpoint<\/strong>:\u00a0<code>https:\/\/lichess.org\/api\/games\/user\/{username}<\/code><\/li>\n\n\n\n<li><strong>Purpose<\/strong>: Fetches games played by a given Lichess user.<\/li>\n<\/ul>\n\n\n\n<p>In this blog, we\u2019ll focus on the&nbsp;<strong>Games<\/strong>&nbsp;endpoint to fetch and display a user\u2019s game history.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>What Is HTTP?<\/strong><br>HTTP (HyperText Transfer Protocol) is the foundation of communication on the web. It defines how messages are formatted and transmitted between clients (like a browser or application) and servers. For example, when your application sends a request to the Lichess API, it uses HTTP to communicate. Common HTTP methods include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>GET<\/strong>: Retrieve data from a server.<\/li>\n\n\n\n<li><strong>POST<\/strong>: Send data to a server.<\/li>\n\n\n\n<li><strong>PUT<\/strong>: Update data on a server.<\/li>\n\n\n\n<li><strong>DELETE<\/strong>: Remove data from a server.<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#the-lichess-api\"><\/a>The Lichess API<\/h4>\n\n\n\n<p>The&nbsp;<strong><a href=\"https:\/\/lichess.org\/api\">Lichess API<\/a><\/strong>&nbsp;is a RESTful API that gives developers access to a wealth of chess-related data. Here are some of its features:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>User Data<\/strong>: Retrieve information about a specific user, such as their rating and games played.<\/li>\n\n\n\n<li><strong>Game Data<\/strong>: Access complete game histories, including moves, openings, and final positions.<\/li>\n\n\n\n<li><strong>Tournaments and Puzzles<\/strong>: Fetch details about tournaments or solve chess puzzles programmatically.<\/li>\n<\/ul>\n\n\n\n<p>In this tutorial, we\u2019ll use the&nbsp;<strong>Games<\/strong>&nbsp;endpoint to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Fetch a specified number of games for a given user.<\/li>\n\n\n\n<li>Include details like the opening name, moves, and final position (FEN).<\/li>\n<\/ol>\n\n\n\n<p>By understanding how endpoints work, you\u2019ll be able to explore other parts of the Lichess API and integrate additional features into your application in the future.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#setting-up-a-react-application\"><\/a>Setting Up a React Application<\/h2>\n\n\n\n<p>In this section, we\u2019ll create a React application from scratch using&nbsp;<code>Create React App<\/code>. This will serve as the foundation for our Lichess API integration.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-1-create-a-new-react-application\"><\/a>Step 1: Create a New React Application<\/h4>\n\n\n\n<p>React is a popular JavaScript library for building user interfaces. To get started, we\u2019ll use a tool called&nbsp;<strong>Create React App<\/strong>, which sets up a new project with all the necessary configurations and dependencies pre-installed.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Open Your Terminal<\/strong><br>You\u2019ll need a terminal or command-line tool to run commands. On Windows, you can use Command Prompt or PowerShell. On macOS or Linux, use the built-in terminal.<\/li>\n\n\n\n<li><strong>Run the Create React App Command<\/strong><br>In your terminal, type\u00a0<code>npx create-react-app lichess-api-app<\/code>. The\u00a0<code>npx<\/code>\u00a0command ensures that you\u2019re using the latest version of Create React App, while\u00a0<code>lichess-api-app<\/code>\u00a0is the name of your project folder. This command downloads and installs all the dependencies required for a React project. It might take a few minutes depending on your internet connection.<\/li>\n\n\n\n<li><strong>Navigate Into Your Project Folder<\/strong><br>Once the installation is complete, use the\u00a0<code>cd lichess-api-app<\/code>\u00a0command to navigate into the folder where your new React project is located.<\/li>\n\n\n\n<li><strong>What\u2019s Inside the Folder?<\/strong><br>Your project folder contains several files and directories:\n<ul class=\"wp-block-list\">\n<li>A\u00a0<code>node_modules<\/code>\u00a0folder with all the dependencies installed for your project.<\/li>\n\n\n\n<li>A\u00a0<code>public<\/code>\u00a0folder that includes static assets like the\u00a0<code>index.html<\/code>\u00a0file.<\/li>\n\n\n\n<li>A\u00a0<code>src<\/code>\u00a0folder, which is the main location for your React components and logic.<\/li>\n\n\n\n<li>A\u00a0<code>package.json<\/code>\u00a0file, which lists project metadata and dependencies.<\/li>\n\n\n\n<li>A\u00a0<code>README.md<\/code>\u00a0file, which contains instructions and information about your project.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>At this stage, your new React application is ready, and you\u2019re set to begin building your project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#open-the-project-in-vs-code\"><\/a>Open the Project in VS Code<\/h2>\n\n\n\n<p>Once your React application is created, the next step is to open it in a code editor. We\u2019ll use&nbsp;<strong>Visual Studio Code (VS Code)<\/strong>, a popular editor for web development.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Launch VS Code<\/strong><br>Open Visual Studio Code from your operating system\u2019s application menu.<\/li>\n\n\n\n<li><strong>Add the Project Folder to Workspace<\/strong><br>In VS Code:<ul><li>Click on\u00a0<strong>File<\/strong>\u00a0in the top menu bar.<\/li><li>Select\u00a0<strong>Add Folder to Workspace<\/strong>.<\/li><li>In the file explorer that appears, navigate to the folder where you created your React project (<code>lichess-api-app<\/code>).<\/li><li>Select the folder and click\u00a0<strong>Add<\/strong>.<\/li><\/ul>This step ensures that all files and folders in your project are accessible from within VS Code.<\/li>\n\n\n\n<li><strong>Explore the Workspace<\/strong><br>Once the folder is added, you\u2019ll see the project structure in the VS Code\u00a0<strong>Explorer<\/strong>\u00a0panel on the left. Key elements include:\n<ul class=\"wp-block-list\">\n<li><strong><code>src<\/code>\u00a0folder<\/strong>: This is where you\u2019ll write your React code.<\/li>\n\n\n\n<li><strong><code>public<\/code>\u00a0folder<\/strong>: Contains the\u00a0<code>index.html<\/code>\u00a0file, where your React application is injected.<\/li>\n\n\n\n<li><strong><code>package.json<\/code><\/strong>: Lists project dependencies and configuration.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Open the Terminal in VS Code<\/strong><br>To run commands directly from VS Code:\n<ul class=\"wp-block-list\">\n<li>Go to the top menu and select\u00a0<strong>View<\/strong>\u00a0<strong>Terminal<\/strong>.<\/li>\n\n\n\n<li>A terminal window will open at the bottom of the editor, starting in your project folder.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Verify Everything is Set Up<\/strong><br>In the terminal, start the development server by typing\u00a0<code>npm start<\/code>. This will run your React application and open it in your default web browser at\u00a0<code>http:\/\/localhost:3000<\/code>.<br>If you see the default React welcome page in your browser, everything is set up correctly.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><strong>Note:<\/strong>&nbsp;If you have another server running on your machine (for example, another React project), you may encounter a message like:<br><em>&#8220;Something is already running on port 3000.&#8221;<\/em><br>In this case, you will be given two options:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Use a Different Port<\/strong>: React will prompt you to run the application on a different port, such as\u00a0<code>http:\/\/localhost:3001<\/code>. You can press\u00a0<code>Y<\/code>\u00a0to confirm.<\/li>\n\n\n\n<li><strong>Shut Down the Other Server<\/strong>: If you prefer to run your application on port 3000, you\u2019ll need to stop the other server. To do this, go to the terminal where the other server is running and press\u00a0<code>Ctrl + C<\/code>\u00a0(or\u00a0<code>Cmd + C<\/code>\u00a0on macOS) to terminate it.<\/li>\n<\/ol>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#introducing-material-ui\"><\/a>Introducing Material UI<\/h2>\n\n\n\n<p>In this section, we\u2019ll enhance the user interface of our React application using&nbsp;<strong>Material UI<\/strong>, a popular library of pre-styled and customizable components. Material UI allows us to quickly build professional, modern-looking interfaces without having to write extensive CSS. By the end of this section, we\u2019ll have a clean and responsive form with the following features:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An input field for the\u00a0<strong>Lichess username<\/strong>.<\/li>\n\n\n\n<li>An input field for the\u00a0<strong>number of games to fetch<\/strong>\u00a0(default set to 50).<\/li>\n\n\n\n<li>A button to\u00a0<strong>trigger the API call<\/strong>\u00a0and fetch the games.<\/li>\n<\/ul>\n\n\n\n<p>This form will lay the groundwork for integrating the Lichess API in the next section.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#why-use-material-ui\"><\/a>Why Use Material UI?<\/h4>\n\n\n\n<p>Material UI (MUI) is based on Google\u2019s Material Design principles, focusing on clean, consistent, and user-friendly interfaces. Here are some reasons to use it:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Pre-Styled Components<\/strong>: Includes a library of pre-designed components like buttons, tables, and input fields.<\/li>\n\n\n\n<li><strong>Customizability<\/strong>: You can easily tweak the styles using inline styling, theming, or CSS overrides.<\/li>\n\n\n\n<li><strong>Accessibility<\/strong>: Material UI components are built with accessibility in mind, making your application more user-friendly.<\/li>\n\n\n\n<li><strong>Ease of Use<\/strong>: You can achieve professional designs with minimal effort, reducing the need to write custom CSS.<\/li>\n<\/ol>\n\n\n\n<p>By using Material UI, we can focus more on building the application logic rather than spending time on UI design from scratch.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-1-install-material-ui\"><\/a>Step 1: Install Material UI<\/h4>\n\n\n\n<p>To begin using Material UI, we need to install the required packages. These include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>[@mui](\/@\/mui)\/material<\/code><\/strong>: The core Material UI component library.<\/li>\n\n\n\n<li><strong><code>[@emotion](\/@\/emotion)\/react<\/code><\/strong>\u00a0and\u00a0<strong><code>[@emotion](\/@\/emotion)\/styled<\/code><\/strong>: Required for styling the Material UI components.<\/li>\n<\/ul>\n\n\n\n<p>Install these packages by running the following command in your terminal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install &#91;@mui](\/@\/mui)\/material &#91;@emotion](\/@\/emotion)\/react &#91;@emotion](\/@\/emotion)\/styled<\/code><\/pre>\n\n\n\n<p>The&nbsp;<code>[@emotion](\/@\/emotion)\/react<\/code>&nbsp;and&nbsp;<code>[@emotion](\/@\/emotion)\/styled<\/code>&nbsp;packages are necessary for Material UI\u2019s styling to work. Once installed, you can start using Material UI components in your project.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-2-create-the-basic-form\"><\/a>Step 2: Create the Basic Form<\/h4>\n\n\n\n<p>Now, we\u2019ll set up a basic form in&nbsp;<code>App.js<\/code>&nbsp;with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An input field for the Lichess username.<\/li>\n\n\n\n<li>An input field for the number of games to fetch (default 50).<\/li>\n\n\n\n<li>A button to fetch games.<\/li>\n<\/ul>\n\n\n\n<p>Replace the content of&nbsp;<code>src\/App.js<\/code>&nbsp;with the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React, { useState } from 'react';\nimport { TextField, Button, Container, Typography } from '&#91;@mui](\/@\/mui)\/material';\n\nfunction App() {\n  const &#91;username, setUsername] = useState('');\n  const &#91;numberOfGames, setNumberOfGames] = useState(50);\n\n  const fetchGames = () => {\n    console.log(`Fetching ${numberOfGames} games for ${username}`);\n  };\n\n  return (\n    &lt;Container>\n      &lt;Typography variant=\"h4\" gutterBottom>\n        Lichess Game Fetcher\n      &lt;\/Typography>\n      &lt;TextField\n        label=\"Lichess Username\"\n        variant=\"outlined\"\n        fullWidth\n        margin=\"normal\"\n        value={username}\n        onChange={(e) => setUsername(e.target.value)}\n      \/>\n      &lt;TextField\n        label=\"Number of Games\"\n        variant=\"outlined\"\n        type=\"number\"\n        fullWidth\n        margin=\"normal\"\n        value={numberOfGames}\n        onChange={(e) => setNumberOfGames(e.target.value)}\n      \/>\n      &lt;Button\n        variant=\"contained\"\n        color=\"primary\"\n        onClick={fetchGames}\n        style={{ marginTop: '20px' }}\n      >\n        Fetch Games\n      &lt;\/Button>\n    &lt;\/Container>\n  );\n}\n\nexport default App;<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-3-understanding-the-code\"><\/a>Step 3: Understanding the Code<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Container<\/strong>: A layout component from Material UI that centers the content and adds padding.<\/li>\n\n\n\n<li><strong>Typography<\/strong>: Used to style text elements like headings and paragraphs. We used it here to create a title for the application.<\/li>\n\n\n\n<li><strong>TextField<\/strong>: A Material UI input component. We added two text fields:\n<ol class=\"wp-block-list\">\n<li>For entering the Lichess username.<\/li>\n\n\n\n<li>For specifying the number of games to fetch.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li><strong>Button<\/strong>: A Material UI button component. When clicked, it triggers the\u00a0<code>fetchGames<\/code>\u00a0function.<\/li>\n<\/ul>\n\n\n\n<p>The&nbsp;<code>useState<\/code>&nbsp;hooks manage the form\u2019s state:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>username<\/code>\u00a0stores the entered Lichess username.<\/li>\n\n\n\n<li><code>numberOfGames<\/code>\u00a0stores the number of games to fetch.<\/li>\n<\/ul>\n\n\n\n<p>The&nbsp;<code>fetchGames<\/code>&nbsp;function logs the entered values to the console. We\u2019ll enhance this function in the next section to fetch data from the Lichess API.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-4-preview-the-form\"><\/a>Step 4: Preview the Form<\/h4>\n\n\n\n<p>Save your changes and check the browser. You should see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A title labeled \u201cLichess Game Fetcher.\u201d<\/li>\n\n\n\n<li>Two input fields for the username and the number of games.<\/li>\n\n\n\n<li>A button labeled \u201cFetch Games.\u201d<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/image.lichess1.org\/display?fmt=webp&amp;h=0&amp;op=resize&amp;path=hollowleaf:ublogBody:EwJiVmR0JQES:g1AK5W4T.png&amp;w=800&amp;sig=0e15da2fa3e5c71e031814a43d7ceaeccb9094cf\" alt=\"image.png\"\/><\/figure>\n\n\n\n<p>At this stage, you\u2019ve built a functional form using Material UI. In the next section, we\u2019ll connect this form to the Lichess API to fetch and display game data.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#fetching-and-displaying-games\"><\/a>Fetching and Displaying Games<\/h2>\n\n\n\n<p>In this section, we\u2019ll integrate the Lichess API into our React application. The goal is to fetch a list of chess games based on the input values (Lichess username and number of games) and display the data in a clean and structured format using a&nbsp;<strong>Material UI Table<\/strong>. We\u2019ll enhance the table to include player details, results, game dates, opening names, final positions, and the sequence of moves.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-1-understand-the-lichess-api-endpoint\"><\/a>Step 1: Understand the Lichess API Endpoint<\/h4>\n\n\n\n<p>The&nbsp;<strong>Games API endpoint<\/strong>&nbsp;retrieves games played by a specific Lichess user. The structure of the endpoint is as follows:<br><strong>Endpoint<\/strong>:<br><code>https:\/\/lichess.org\/api\/games\/user\/{username}<\/code><br>Query parameters:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>max<\/code><\/strong>: Specifies the maximum number of games to fetch (user input, default 50).<\/li>\n\n\n\n<li><strong><code>opening<\/code><\/strong>: Includes the opening name in the response if set to\u00a0<code>true<\/code>.<\/li>\n\n\n\n<li><strong><code>moves<\/code><\/strong>: Retrieves the complete move list if set to\u00a0<code>true<\/code>.<\/li>\n\n\n\n<li><strong><code>lastFen<\/code><\/strong>: Includes the final board position in FEN format if set to\u00a0<code>true<\/code>.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-2-fetch-games-from-the-lichess-api\"><\/a>Step 2: Fetch Games from the Lichess API<\/h4>\n\n\n\n<p>To retrieve games in NDJSON format:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Build the API URL dynamically with user inputs.<\/li>\n\n\n\n<li>Set the\u00a0<code>Accept<\/code>\u00a0header to request NDJSON.<\/li>\n\n\n\n<li>Parse the NDJSON response and store it in a state variable for rendering.<\/li>\n<\/ol>\n\n\n\n<p>Here\u2019s the function to fetch games:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const fetchGames = async () => {\n  if (!username) {\n    alert(\"Please enter a Lichess username.\"); \/\/ Validate username input.\n    return;\n  }\n\n  const url = `https:\/\/lichess.org\/api\/games\/user\/${username}?max=${numberOfGames}&amp;opening=true&amp;moves=true&amp;lastFen=true`;\n\n  try {\n    const response = await fetch(url, {\n      headers: { Accept: 'application\/x-ndjson' }, \/\/ Request NDJSON format.\n    });\n\n    const text = await response.text(); \/\/ Read the NDJSON response as plain text.\n    const parsedGames = text\n      .trim() \/\/ Remove extra spaces or newlines.\n      .split('\\n') \/\/ Split the NDJSON by newline to separate game data.\n      .map((line) => JSON.parse(line)); \/\/ Parse each line into a JSON object.\n    setGames(parsedGames); \/\/ Update the state with the parsed game data.\n  } catch (error) {\n    console.error(\"Error fetching games:\", error); \/\/ Log any errors to the console.\n    alert(\"Failed to fetch games. Please try again.\"); \/\/ Show an error message to the user.\n  }\n};<\/code><\/pre>\n\n\n\n<p>Explanation of code:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Validates the input to ensure a username is provided.<\/li>\n\n\n\n<li>Dynamically constructs the API URL using the username and number of games, with parameters to include opening names, moves, and the final board position in FEN format.<\/li>\n\n\n\n<li>Sends a GET request to the Lichess API, requesting data in NDJSON format by setting the appropriate\u00a0<code>Accept<\/code>\u00a0header.<\/li>\n\n\n\n<li>Processes the NDJSON response by:\n<ul class=\"wp-block-list\">\n<li>Reading it as plain text.<\/li>\n\n\n\n<li>Splitting it into lines (one line per game).<\/li>\n\n\n\n<li>Parsing each line into a JSON object.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Updates the\u00a0<code>games<\/code>\u00a0state with the parsed data, triggering a UI update to display the results.<\/li>\n\n\n\n<li>Handles errors by logging them to the console and showing an alert to the user.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-3-add-a-table-to-display-games\"><\/a>Step 3: Add a Table to Display Games<\/h4>\n\n\n\n<p>We\u2019ll use Material UI\u2019s&nbsp;<code>Table<\/code>&nbsp;component to dynamically display the game data fetched from the Lichess API. Each row will represent a single game, with the following columns:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>White<\/strong>: Displays the username and rating of the White player.<\/li>\n\n\n\n<li><strong>Black<\/strong>: Displays the username and rating of the Black player.<\/li>\n\n\n\n<li><strong>Result<\/strong>: Indicates the result of the game (e.g., &#8220;White Wins,&#8221; &#8220;Black Wins,&#8221; or &#8220;Draw&#8221;).<\/li>\n\n\n\n<li><strong>Date<\/strong>: Shows the date when the game was played, formatted for readability.<\/li>\n\n\n\n<li><strong>Opening<\/strong>: Displays the name of the opening used in the game, if available.<\/li>\n\n\n\n<li><strong>Last Position<\/strong>: Shows the final board position in FEN format.<\/li>\n\n\n\n<li><strong>Moves<\/strong>: Displays the sequence of moves played during the game.<\/li>\n<\/ul>\n\n\n\n<p>Here\u2019s the updated implementation of the table with inline comments explaining each part:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{games.length > 0 &amp;&amp; ( \/\/ Check if games are available before rendering the table.\n  &lt;Table sx={{ marginTop: '20px' }}> {\/* Material UI Table with spacing above *\/}\n    &lt;TableHead>\n      &lt;TableRow>\n        &lt;TableCell>White&lt;\/TableCell> {\/* Column for White player's username and rating *\/}\n        &lt;TableCell>Black&lt;\/TableCell> {\/* Column for Black player's username and rating *\/}\n        &lt;TableCell>Result&lt;\/TableCell> {\/* Column for game result *\/}\n        &lt;TableCell>Date&lt;\/TableCell> {\/* Column for game date *\/}\n        &lt;TableCell>Opening&lt;\/TableCell> {\/* Column for opening name *\/}\n        &lt;TableCell>Last Position&lt;\/TableCell> {\/* Column for final board position (FEN) *\/}\n        &lt;TableCell>Moves&lt;\/TableCell> {\/* Column for sequence of moves *\/}\n      &lt;\/TableRow>\n    &lt;\/TableHead>\n    &lt;TableBody>\n      {\/* Loop through the games array to generate a table row for each game *\/}\n      {games.map((game, index) => (\n        &lt;TableRow key={index}> {\/* Unique key for each row to optimize rendering *\/}\n          {\/* White player's details *\/}\n          &lt;TableCell>\n            {game.players.white.user?.name || \"Anonymous\"} {\/* Username or fallback *\/}\n            {\" \"}({game.players.white.rating}) {\/* Rating *\/}\n          &lt;\/TableCell>\n\n          {\/* Black player's details *\/}\n          &lt;TableCell>\n            {game.players.black.user?.name || \"Anonymous\"} {\/* Username or fallback *\/}\n            {\" \"}({game.players.black.rating}) {\/* Rating *\/}\n          &lt;\/TableCell>\n\n          {\/* Game result *\/}\n          &lt;TableCell>\n            {game.winner\n              ? game.winner === \"white\"\n                ? \"White Wins\" \/* If winner is White *\/\n                : \"Black Wins\" \/* If winner is Black *\/\n              : \"Draw\" \/* If no winner *\/}\n          &lt;\/TableCell>\n\n          {\/* Game date *\/}\n          &lt;TableCell>\n            {new Date(game.createdAt).toLocaleDateString(\"en-US\", {\n              year: \"numeric\",\n              month: \"short\",\n              day: \"numeric\",\n            })} {\/* Format timestamp into readable date *\/}\n          &lt;\/TableCell>\n\n          {\/* Opening name *\/}\n          &lt;TableCell>\n            {game.opening?.name || \"Unknown\"} {\/* Display opening name or fallback *\/}\n          &lt;\/TableCell>\n\n          {\/* Final board position in FEN format *\/}\n          &lt;TableCell>\n            {game.lastFen} {\/* Display the final board position *\/}\n          &lt;\/TableCell>\n\n          {\/* Moves played in the game *\/}\n          &lt;TableCell>\n            {game.moves ? game.moves : \"Moves not available\"} {\/* Display moves or fallback *\/}\n          &lt;\/TableCell>\n        &lt;\/TableRow>\n      ))}\n    &lt;\/TableBody>\n  &lt;\/Table>\n)}<\/code><\/pre>\n\n\n\n<p>Explanation of the Code<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><code>games.length > 0<\/code>\u00a0Check<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Ensures that the table is only rendered if the\u00a0<code>games<\/code>\u00a0array contains data.<\/li>\n\n\n\n<li>Prevents rendering an empty table when no games are available.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Material UI Table Structure<\/strong>:\n<ul class=\"wp-block-list\">\n<li>The\u00a0<code>&lt;Table><\/code>\u00a0component serves as the container for the table.<\/li>\n\n\n\n<li><code>&lt;TableHead><\/code>\u00a0defines the table header row, with\u00a0<code>&lt;TableCell><\/code>\u00a0elements for each column title.<\/li>\n\n\n\n<li><code>&lt;TableBody><\/code>\u00a0contains the dynamic rows generated from the\u00a0<code>games<\/code>\u00a0array.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Looping Through the Games Array<\/strong>:\n<ul class=\"wp-block-list\">\n<li>The\u00a0<code>map<\/code>\u00a0method is used to iterate over the\u00a0<code>games<\/code>\u00a0array.<\/li>\n\n\n\n<li>Each iteration creates a\u00a0<code>&lt;TableRow><\/code>\u00a0representing a single game.<\/li>\n\n\n\n<li>Unique keys (<code>key={index}<\/code>) are assigned to each\u00a0<code>&lt;TableRow><\/code>\u00a0for efficient rendering.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Fallback Values<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Fallback values like\u00a0<code>\"Anonymous\"<\/code>,\u00a0<code>\"Unknown\"<\/code>, or\u00a0<code>\"Moves not available\"<\/code>\u00a0ensure the application handles missing data gracefully.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Dynamic Data Rendering<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Player details, results, dates, openings, FEN, and moves are extracted from the\u00a0<code>game<\/code>\u00a0object and displayed in corresponding\u00a0<code>&lt;TableCell><\/code>\u00a0elements.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Date Formatting<\/strong>:\n<ul class=\"wp-block-list\">\n<li>The\u00a0<code>createdAt<\/code>\u00a0field is a timestamp in milliseconds. It\u2019s converted to a human-readable format using\u00a0<code>toLocaleDateString<\/code>.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Here is the final code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React, { useState } from 'react';\nimport {\n  TextField,\n  Button,\n  Container,\n  Typography,\n  Box,\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableRow,\n} from '&#91;@mui](\/@\/mui)\/material';\n\nfunction App() {\n  const &#91;username, setUsername] = useState(''); \/\/ State for the Lichess username input.\n  const &#91;numberOfGames, setNumberOfGames] = useState(50); \/\/ State for the number of games to fetch (default is 50).\n  const &#91;games, setGames] = useState(&#91;]); \/\/ State to store the fetched games data.\n\n  \/\/ Function to fetch games from the Lichess API.\n  const fetchGames = async () => {\n    \/\/ Validate input: Ensure a username has been provided.\n    if (!username) {\n      alert(\"Please enter a Lichess username.\");\n      return;\n    }\n\n    \/\/ Construct the API URL using the username and number of games.\n    const url = `https:\/\/lichess.org\/api\/games\/user\/${username}?max=${numberOfGames}&amp;opening=true&amp;moves=true&amp;lastFen=true`;\n\n    try {\n      \/\/ Make the API request, specifying that we want NDJSON data.\n      const response = await fetch(url, {\n        headers: { Accept: 'application\/x-ndjson' },\n      });\n\n      \/\/ Read the response as text and parse the NDJSON data into an array of objects.\n      const text = await response.text();\n      const parsedGames = text\n        .trim() \/\/ Remove any leading or trailing whitespace.\n        .split('\\n') \/\/ Split the NDJSON response into individual lines.\n        .map((line) => JSON.parse(line)); \/\/ Parse each line as JSON.\n\n      \/\/ Update the state with the parsed games data.\n      setGames(parsedGames);\n    } catch (error) {\n      console.error(\"Error fetching games:\", error); \/\/ Log errors to the console.\n      alert(\"Failed to fetch games. Please try again.\"); \/\/ Show an alert to the user.\n    }\n  };\n\n  return (\n    &lt;Container>\n      {\/* Page Title *\/}\n      &lt;Typography variant=\"h4\" gutterBottom>\n        Lichess API: Fetch Games\n      &lt;\/Typography>\n\n      {\/* Input Form *\/}\n      &lt;Box\n        sx={{\n          display: 'flex', \/\/ Display inputs and button in a row.\n          alignItems: 'center', \/\/ Align items vertically.\n          gap: '16px', \/\/ Add spacing between elements.\n          marginTop: '20px', \/\/ Add spacing above the form.\n        }}\n      >\n        {\/* Input for Lichess username *\/}\n        &lt;TextField\n          label=\"Lichess Username\"\n          variant=\"outlined\"\n          value={username} \/\/ Bind the value to the username state.\n          onChange={(e) => setUsername(e.target.value)} \/\/ Update the username state on input change.\n          style={{ flex: 2 }} \/\/ Set the size of this input field relative to the button.\n        \/>\n        {\/* Input for number of games *\/}\n        &lt;TextField\n          label=\"Number of Games\"\n          variant=\"outlined\"\n          type=\"number\" \/\/ Restrict input to numbers.\n          value={numberOfGames} \/\/ Bind the value to the numberOfGames state.\n          onChange={(e) => setNumberOfGames(e.target.value)} \/\/ Update the numberOfGames state on input change.\n          style={{ flex: 1 }} \/\/ Make this input smaller than the username input.\n        \/>\n        {\/* Button to trigger the fetchGames function *\/}\n        &lt;Button\n          variant=\"contained\"\n          color=\"primary\"\n          onClick={fetchGames} \/\/ Trigger the fetchGames function when clicked.\n        >\n          Fetch Games\n        &lt;\/Button>\n      &lt;\/Box>\n\n      {\/* Table to display fetched game data *\/}\n      {games.length > 0 &amp;&amp; ( \/\/ Render the table only if there are games to display.\n        &lt;Table sx={{ marginTop: '20px' }}>\n          &lt;TableHead>\n            &lt;TableRow>\n              &lt;TableCell>White&lt;\/TableCell> {\/* Column header for White player details *\/}\n              &lt;TableCell>Black&lt;\/TableCell> {\/* Column header for Black player details *\/}\n              &lt;TableCell>Result&lt;\/TableCell> {\/* Column header for game result *\/}\n              &lt;TableCell>Date&lt;\/TableCell> {\/* Column header for game date *\/}\n              &lt;TableCell>Opening&lt;\/TableCell> {\/* Column header for opening name *\/}\n              &lt;TableCell>Last Position&lt;\/TableCell> {\/* Column header for FEN *\/}\n              &lt;TableCell>Moves&lt;\/TableCell> {\/* Column header for game moves *\/}\n            &lt;\/TableRow>\n          &lt;\/TableHead>\n          &lt;TableBody>\n            {\/* Loop through the games array to generate a table row for each game *\/}\n            {games.map((game, index) => (\n              &lt;TableRow key={index}> {\/* Unique key for each row *\/}\n                {\/* White player details *\/}\n                &lt;TableCell>\n                  {game.players.white.user?.name || \"Anonymous\"} {\/* Username or fallback *\/}\n                  {\" \"}({game.players.white.rating}) {\/* Rating *\/}\n                &lt;\/TableCell>\n                {\/* Black player details *\/}\n                &lt;TableCell>\n                  {game.players.black.user?.name || \"Anonymous\"} {\/* Username or fallback *\/}\n                  {\" \"}({game.players.black.rating}) {\/* Rating *\/}\n                &lt;\/TableCell>\n                {\/* Game result *\/}\n                &lt;TableCell>\n                  {game.winner\n                    ? game.winner === \"white\"\n                      ? \"White Wins\" \/* If White is the winner *\/\n                      : \"Black Wins\" \/* If Black is the winner *\/\n                    : \"Draw\" \/* If no winner *\/}\n                &lt;\/TableCell>\n                {\/* Game date *\/}\n                &lt;TableCell>\n                  {new Date(game.createdAt).toLocaleDateString(\"en-US\", {\n                    year: \"numeric\",\n                    month: \"short\",\n                    day: \"numeric\",\n                  })} {\/* Convert timestamp to readable date *\/}\n                &lt;\/TableCell>\n                {\/* Opening name *\/}\n                &lt;TableCell>\n                  {game.opening?.name || \"Unknown\"} {\/* Display opening name or fallback *\/}\n                &lt;\/TableCell>\n                {\/* Final board position (FEN) *\/}\n                &lt;TableCell>\n                  {game.lastFen} {\/* Display the FEN or fallback *\/}\n                &lt;\/TableCell>\n                {\/* Moves played in the game *\/}\n                &lt;TableCell>\n                  {game.moves ? game.moves : \"Moves not available\"} {\/* Display moves or fallback *\/}\n                &lt;\/TableCell>\n              &lt;\/TableRow>\n            ))}\n          &lt;\/TableBody>\n        &lt;\/Table>\n      )}\n    &lt;\/Container>\n  );\n}\n\nexport default App;<\/code><\/pre>\n\n\n\n<p>When you enter a Lichess Username and click on Fetch, you should not see the following:<br><img decoding=\"async\" src=\"https:\/\/image.lichess1.org\/display?fmt=webp&amp;h=0&amp;op=resize&amp;path=hollowleaf:ublogBody:zYFlZsPBPBsH:XniEGCUc.png&amp;w=800&amp;sig=fe0c15f4549a6004f5fcc45006ed5ed003133fed\" alt=\"image.png\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#formatting-our-output\"><\/a>Formatting Our Output<\/h2>\n\n\n\n<p>In this section, we\u2019ll take the code from&nbsp;<strong>Section 4<\/strong>&nbsp;and format the output into the final design. The goal is to enhance the user experience by structuring the game data into two columns:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Column A<\/strong>: Displays the final chessboard position using the\u00a0<code>react-chessboard<\/code>\u00a0library.<\/li>\n\n\n\n<li><strong>Column B<\/strong>: Contains detailed game information organized into multiple rows, such as player names and ratings, game results, date and time, opening name, and moves.<\/li>\n<\/ul>\n\n\n\n<p>We\u2019ll explain step by step how to achieve this transformation.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-1-install-react-chessboard\"><\/a>Step 1: Install&nbsp;<code>react-chessboard<\/code><\/h4>\n\n\n\n<p>To display the chessboard for the final position, we\u2019ll use the&nbsp;<code>react-chessboard<\/code>&nbsp;library. If you haven\u2019t already installed it, run the following command in your project directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install react-chessboard<\/code><\/pre>\n\n\n\n<p>After installing, you can import the&nbsp;<code>Chessboard<\/code>&nbsp;component at the top of your file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Chessboard } from \"react-chessboard\";<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-2-modify-the-table-layout\"><\/a>Step 2: Modify the Table Layout<\/h4>\n\n\n\n<p>In Section 4, the game data was displayed in a single-row table with columns for White, Black, Result, Date, Opening, Final Position, and Moves. We\u2019ll now restructure the table:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Combine all game details into\u00a0<strong>Column B<\/strong>\u00a0as a vertical layout.<\/li>\n\n\n\n<li>Use\u00a0<strong>Column A<\/strong>\u00a0to display the chessboard with the final position (<code>lastFen<\/code>).<\/li>\n<\/ul>\n\n\n\n<p><strong>Key Changes<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Replace individual\u00a0<code>&lt;TableCell><\/code>\u00a0elements for game details with a\u00a0<code>&lt;Box><\/code>\u00a0containing rows for:\n<ol class=\"wp-block-list\">\n<li>Player names and ratings.<\/li>\n\n\n\n<li>Game result.<\/li>\n\n\n\n<li>Date and time.<\/li>\n\n\n\n<li>Opening name.<\/li>\n\n\n\n<li>Moves.<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-3-configure-the-chessboard-in-column-a\"><\/a>Step 3: Configure the Chessboard in Column A<\/h4>\n\n\n\n<p>The&nbsp;<code>react-chessboard<\/code>&nbsp;library provides an interactive chessboard that can display a game position using the FEN format. For our use case:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Use the\u00a0<code>lastFen<\/code>\u00a0field from the API response to set the final position.<\/li>\n\n\n\n<li>Disable dragging of chess pieces using the\u00a0<code>arePiecesDraggable={false}<\/code>\u00a0property.<\/li>\n\n\n\n<li>Adjust the size of the chessboard to\u00a0<code>200px<\/code>\u00a0using\u00a0<code>boardWidth<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>Here\u2019s how to integrate the chessboard into&nbsp;<strong>Column A<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Chessboard\n  position={game.lastFen || \"start\"} \/\/ Use the final FEN position or fallback to the starting position.\n  arePiecesDraggable={false} \/\/ Disable dragging on the chessboard.\n  boardWidth={200} \/\/ Set the width of the chessboard.\n\/><\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-4-organize-game-details-in-column-b\"><\/a>Step 4: Organize Game Details in Column B<\/h4>\n\n\n\n<p>To format the game details:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Use a\u00a0<code>Box<\/code>\u00a0component with\u00a0<code>flexDirection: \"column\"<\/code>\u00a0to organize rows vertically.<\/li>\n\n\n\n<li>Format each piece of information (e.g., players, result, date) using\u00a0<code>&lt;Typography><\/code>\u00a0for consistent styling.<\/li>\n\n\n\n<li>Add spacing between rows using the\u00a0<code>gap<\/code>\u00a0property.<\/li>\n<\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;Box sx={{ display: \"flex\", flexDirection: \"column\", gap: \"8px\" }}>\n  {\/* Row 1: Players and ratings *\/}\n  &lt;Typography variant=\"h6\">\n    {game.players.white.user?.name || \"Anonymous\"} ({game.players.white.rating}) vs{\" \"}\n    {game.players.black.user?.name || \"Anonymous\"} ({game.players.black.rating})\n  &lt;\/Typography>\n\n  {\/* Row 2: Game result *\/}\n  &lt;Typography variant=\"body1\">\n    Result:{\" \"}\n    {game.winner\n      ? game.winner === \"white\"\n        ? \"White Wins\"\n        : \"Black Wins\"\n      : \"Draw\"}\n  &lt;\/Typography>\n\n  {\/* Row 3: Date and time played *\/}\n  &lt;Typography variant=\"body2\">\n    Date:{\" \"}\n    {new Date(game.createdAt).toLocaleString(\"en-US\", {\n      year: \"numeric\",\n      month: \"short\",\n      day: \"numeric\",\n      hour: \"2-digit\",\n      minute: \"2-digit\",\n    })}\n  &lt;\/Typography>\n\n  {\/* Row 4: Opening name *\/}\n  &lt;Typography variant=\"body2\">\n    Opening: {game.opening?.name || \"Unknown\"}\n  &lt;\/Typography>\n\n  {\/* Row 5: Moves played in the game *\/}\n  &lt;Typography variant=\"body2\" sx={{ whiteSpace: \"pre-wrap\" }}>\n    Moves: {game.moves || \"Moves not available\"}\n  &lt;\/Typography>\n&lt;\/Box><\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#step-5-final-code\"><\/a>Step 5: Final Code<\/h4>\n\n\n\n<p>Here\u2019s the final code after applying all formatting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React, { useState } from \"react\";\nimport {\n  TextField,\n  Button,\n  Container,\n  Typography,\n  Box,\n  Table,\n  TableBody,\n  TableCell,\n  TableRow,\n} from \"&#91;@mui](\/@\/mui)\/material\";\nimport { Chessboard } from \"react-chessboard\"; \/\/ Import Chessboard component.\n\nfunction App() {\n  \/\/ State for the Lichess username input.\n  const &#91;username, setUsername] = useState(\"\");\n\n  \/\/ State for the number of games to fetch (default is 50).\n  const &#91;numberOfGames, setNumberOfGames] = useState(50);\n\n  \/\/ State to store the fetched games data.\n  const &#91;games, setGames] = useState(&#91;]);\n\n  \/\/ Function to fetch games from the Lichess API.\n  const fetchGames = async () => {\n    \/\/ Validate input: Ensure a username has been provided.\n    if (!username) {\n      alert(\"Please enter a Lichess username.\");\n      return;\n    }\n\n    \/\/ Construct the API URL using the username and number of games.\n    const url = `https:\/\/lichess.org\/api\/games\/user\/${username}?max=${numberOfGames}&amp;opening=true&amp;moves=true&amp;lastFen=true`;\n\n    try {\n      \/\/ Make the API request, specifying that we want NDJSON data.\n      const response = await fetch(url, {\n        headers: { Accept: \"application\/x-ndjson\" },\n      });\n\n      \/\/ Read the response as text and parse the NDJSON data into an array of objects.\n      const text = await response.text();\n      const parsedGames = text\n        .trim() \/\/ Remove any leading or trailing whitespace.\n        .split(\"\\n\") \/\/ Split the NDJSON response into individual lines.\n        .map((line) => JSON.parse(line)); \/\/ Parse each line as JSON.\n\n      \/\/ Update the state with the parsed games data.\n      setGames(parsedGames);\n    } catch (error) {\n      console.error(\"Error fetching games:\", error); \/\/ Log errors to the console.\n      alert(\"Failed to fetch games. Please try again.\"); \/\/ Show an alert to the user.\n    }\n  };\n\n  return (\n    &lt;Container>\n      {\/* Page Title *\/}\n      &lt;Typography variant=\"h4\" gutterBottom>\n        Lichess API: Fetch Games\n      &lt;\/Typography>\n\n      {\/* Input Form *\/}\n      &lt;Box\n        sx={{\n          display: \"flex\", \/\/ Display inputs and button in a row.\n          alignItems: \"center\", \/\/ Align items vertically.\n          gap: \"16px\", \/\/ Add spacing between elements.\n          marginTop: \"20px\", \/\/ Add spacing above the form.\n        }}\n      >\n        {\/* Input for Lichess username *\/}\n        &lt;TextField\n          label=\"Lichess Username\"\n          variant=\"outlined\"\n          value={username} \/\/ Bind the value to the username state.\n          onChange={(e) => setUsername(e.target.value)} \/\/ Update the username state on input change.\n          style={{ flex: 2 }} \/\/ Set the size of this input field relative to the button.\n        \/>\n        {\/* Input for number of games *\/}\n        &lt;TextField\n          label=\"Number of Games\"\n          variant=\"outlined\"\n          type=\"number\" \/\/ Restrict input to numbers.\n          value={numberOfGames} \/\/ Bind the value to the numberOfGames state.\n          onChange={(e) => setNumberOfGames(e.target.value)} \/\/ Update the numberOfGames state on input change.\n          style={{ flex: 1 }} \/\/ Make this input smaller than the username input.\n        \/>\n        {\/* Button to trigger the fetchGames function *\/}\n        &lt;Button\n          variant=\"contained\"\n          color=\"primary\"\n          onClick={fetchGames} \/\/ Trigger the fetchGames function when clicked.\n        >\n          Fetch Games\n        &lt;\/Button>\n      &lt;\/Box>\n\n      {\/* Table to display fetched game data *\/}\n      {games.length > 0 &amp;&amp; (\n        &lt;Table sx={{ marginTop: \"20px\" }}>\n          &lt;TableBody>\n            {\/* Loop through the games array to generate rows for each game *\/}\n            {games.map((game, index) => (\n              &lt;TableRow key={index}>\n                {\/* Column A: Chessboard *\/}\n                &lt;TableCell>\n                  &lt;Chessboard\n                    position={game.lastFen || \"start\"} \/\/ Use the final FEN position or fallback to the starting position.\n                    arePiecesDraggable={false} \/\/ Disable dragging on the chessboard.\n                    boardWidth={200} \/\/ Set the width of the chessboard.\n                  \/>\n                &lt;\/TableCell>\n\n                {\/* Column B: Game details *\/}\n                &lt;TableCell>\n                  &lt;Box\n                    sx={{\n                      display: \"flex\", \/\/ Use a flex container.\n                      flexDirection: \"column\", \/\/ Stack rows vertically.\n                      gap: \"8px\", \/\/ Add spacing between rows.\n                    }}\n                  >\n                    {\/* Row 1: Players and ratings *\/}\n                    &lt;Typography variant=\"h6\">\n                      {game.players.white.user?.name || \"Anonymous\"} ({game.players.white.rating}) vs{\" \"}\n                      {game.players.black.user?.name || \"Anonymous\"} ({game.players.black.rating})\n                    &lt;\/Typography>\n\n                    {\/* Row 2: Game result *\/}\n                    &lt;Typography variant=\"body1\">\n                      Result:{\" \"}\n                      {game.winner\n                        ? game.winner === \"white\"\n                          ? \"White Wins\"\n                          : \"Black Wins\"\n                        : \"Draw\"}\n                    &lt;\/Typography>\n\n                    {\/* Row 3: Date and time played *\/}\n                    &lt;Typography variant=\"body2\">\n                      Date:{\" \"}\n                      {new Date(game.createdAt).toLocaleString(\"en-US\", {\n                        year: \"numeric\",\n                        month: \"short\",\n                        day: \"numeric\",\n                        hour: \"2-digit\",\n                        minute: \"2-digit\",\n                      })}\n                    &lt;\/Typography>\n\n                    {\/* Row 4: Opening name *\/}\n                    &lt;Typography variant=\"body2\">\n                      Opening: {game.opening?.name || \"Unknown\"}\n                    &lt;\/Typography>\n\n                    {\/* Row 5: Moves played in the game *\/}\n                    &lt;Typography variant=\"body2\" sx={{ whiteSpace: \"pre-wrap\" }}>\n                      Moves: {game.moves || \"Moves not available\"}\n                    &lt;\/Typography>\n                  &lt;\/Box>\n                &lt;\/TableCell>\n              &lt;\/TableRow>\n            ))}\n          &lt;\/TableBody>\n        &lt;\/Table>\n      )}\n    &lt;\/Container>\n  );\n}\n\nexport default App;<\/code><\/pre>\n\n\n\n<p>Your final application should look like the following:<br><img decoding=\"async\" src=\"https:\/\/image.lichess1.org\/display?fmt=webp&amp;h=0&amp;op=resize&amp;path=hollowleaf:ublogBody:LtgrN0xXSXFP:LbzbC2xF.png&amp;w=800&amp;sig=65f02aa5a80cc5d3d997d91579d5004024375fde\" alt=\"image.png\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#summary\"><\/a>Summary<\/h2>\n\n\n\n<p>In this blog, we explored the exciting intersection of chess and web development by building a React application powered by the Lichess API. We started by understanding the basics of RESTful APIs and how they enable seamless interaction between applications. Using the Lichess API, we fetched user-specific chess games, parsed the data, and displayed it in a clean and interactive format. Along the way, we integrated Material UI for styling and&nbsp;<code>react-chessboard<\/code>&nbsp;to visually represent the final positions of games, creating an application that is both functional and visually appealing.<br>Our final application features a two-column layout: one column displays the final position of each game on a chessboard, while the other provides detailed information about the game, such as player names and ratings, results, openings, dates, and moves. By organizing the data in this way, we ensured a clear and user-friendly interface. We also focused on best practices, such as robust error handling and responsive design, to make the application reliable and adaptable.<br>This project is just the beginning of what you can create with the Lichess API. Whether you\u2019re looking to build analysis tools, create educational apps, or experiment with interactive chessboard visualizations, the possibilities are endless. By combining your passion for chess with the skills you\u2019ve learned here, you\u2019re equipped to innovate and bring your ideas to life. The chessboard is your canvas\u2014let your creativity take the lead!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><a href=\"https:\/\/lichess.org\/@\/HollowLeaf\/blog\/chess-web-programming-part-seven-lichess-api\/6MgfKoeh#learn-more\"><\/a>Learn More<\/h3>\n\n\n\n<p>Here are the tools and resources we used in this article to build our Lichess game viewer application. Each of these is essential for recreating and understanding the project:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><a href=\"https:\/\/lichess.org\/api\">Lichess API<\/a><\/strong>: The Lichess API is the backbone of this project, providing access to chess game data. Explore its extensive capabilities and learn how to fetch games, puzzles, and more.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/reactjs.org\/\">React<\/a><\/strong>: React is the framework we used to build this dynamic and interactive application. Learn how to create components, manage state, and build engaging user interfaces.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/mui.com\/\">Material UI<\/a><\/strong>: Material UI is the library we used to style the application and create components like tables, text fields, and buttons. Explore its components and theming options to enhance your React apps.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/github.com\/Clariity\/react-chessboard\">react-chessboard<\/a><\/strong>: This library allowed us to display the final position of games as a static chessboard. Learn how to use it to create visually appealing chessboard components in your applications.<\/li>\n\n\n\n<li><strong><a href=\"https:\/\/code.visualstudio.com\/\">Visual Studio Code<\/a><\/strong>: We used VS Code as our code editor throughout this project. It\u2019s a powerful tool for coding, debugging, and managing projects. Download it to streamline your development workflow.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Working with the Lichess API My journey into programming chess applications started with&nbsp;Chessboard Magic, a personal project that turned into a platform with over 34 unique chess-based applications. This blog continues my Chess Web Programming series, diving into one of the most exciting aspects of modern development: working with APIs. In this installment, we\u2019ll explore [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":48,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-47","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/posts\/47","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/comments?post=47"}],"version-history":[{"count":1,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/posts\/47\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/posts\/47\/revisions\/49"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/media\/48"}],"wp:attachment":[{"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/media?parent=47"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/categories?post=47"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.chessboardmagic.com\/index.php\/wp-json\/wp\/v2\/tags?post=47"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}