<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ documentation - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ documentation - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 13 May 2026 22:44:33 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/documentation/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Create REST API Documentation in Node.js Using Scalar ]]>
                </title>
                <description>
                    <![CDATA[ A REST API documentation is a guide that explains how clients can make use of the REST APIs in an application. It details the available endpoints, how to send requests and what responses to expect. It ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rest-api-documentation-with-scalar/</link>
                <guid isPermaLink="false">699f1d4e6049477bf67a9ad8</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ openai ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Orim Dominic Adah ]]>
                </dc:creator>
                <pubDate>Wed, 25 Feb 2026 16:03:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5fc16e412cae9c5b190b6cdd/ec5d63f1-d65f-4852-a297-9c517fc76e2f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A REST API documentation is a guide that explains how clients can make use of the REST APIs in an application. It details the available endpoints, how to send requests and what responses to expect. It may also contain explanations of concepts that are specific to the scope of the application.</p>
<p>Without API documentation, application development is considered incomplete because developers cannot build software to interact with it, rendering the application effectively useless.</p>
<p>In this article, you will learn how to create beautiful REST API documentation that also allows you to test the APIs for free using an OpenAPI specification and Scalar in Node.js projects. You will use <a href="https://github.com/asteasolutions/zod-to-openapi">asteasolutions/zod-to-openapi</a> to generate OpenAPI specification and use Scalar to create a web page from the specification.</p>
<p>To get the most out of this article, you should have experience developing REST APIs with Express or NestJS. You should also have experience with documenting REST APIs and using <a href="https://zod.dev/">zod</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-rest-api-documentation-tools-for-nodejs">REST API Documentation Tools for Node.js</a></p>
<ul>
<li><p><a href="#heading-swagger">Swagger</a></p>
</li>
<li><p><a href="#heading-postman">Postman</a></p>
</li>
<li><p><a href="#heading-redoc">ReDoc</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-zod-to-openapi-and-scalar-for-rest-api-documentation">zod-to-openapi and Scalar for REST API Documentation</a></p>
<ul>
<li><a href="#heading-how-zod-to-openapi-works-with-scalar">How zod-to-openapi Works with Scalar</a></li>
</ul>
</li>
<li><p><a href="#heading-benefits-of-using-zod-to-openapi-and-scalar-to-create-rest-api-documentation">Benefits of Using zod-to-openapi and Scalar to Create REST API Documentation</a></p>
<ul>
<li><p><a href="#heading-openapi-specification-support">OpenAPI Specification Support</a></p>
</li>
<li><p><a href="#heading-open-source-and-free-to-use">Open Source and Free to Use</a></p>
</li>
<li><p><a href="#heading-better-documentation-experience">Better Documentation Experience</a></p>
</li>
<li><p><a href="#heading-developer-friendly-ui">Developer-friendly UI</a></p>
</li>
<li><p><a href="#heading-markdown-support">Markdown Support</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-how-to-create-the-api-documentation">How to Create the API Documentation</a></p>
<ul>
<li><p><a href="#heading-set-up-the-project">Set up the Project</a></p>
</li>
<li><p><a href="#heading-how-to-set-up-zod-to-openapi">How to Set Up zod-to-openapi</a></p>
</li>
<li><p><a href="#heading-how-to-generate-the-documentation-ui-with-scalar">How to Generate the Documentation UI with Scalar</a></p>
</li>
<li><p><a href="#heading-document-the-endpoints">Document the Endpoints</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-how-to-use-scalar-with-nestjs">How to Use Scalar with NestJS</a></p>
</li>
<li><p><a href="#heading-how-to-resolve-content-security-policy-csp-errors-when-used-with-helmet">How to Resolve Content Security Policy (CSP) Errors When Used with Helmet</a></p>
</li>
<li><p><a href="#heading-absence-of-asyncapi-documentation-feature">Absence of AsyncAPI Documentation Feature</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-rest-api-documentation-tools-for-nodejs">REST API Documentation Tools for Node.js</h2>
<p>A variety of tools already exist for documenting REST APIs and they have different strengths and weaknesses depending on their use case. While some of them are completely free to use, others operate a freemium model, and while some have an interface for testing APIs, others have a presentation-only user interface (UI).</p>
<p>Some of the most popular tools for documenting REST APIs in Node.js projects are listed below:</p>
<ul>
<li><p>Swagger</p>
</li>
<li><p>Postman</p>
</li>
<li><p>Redoc</p>
</li>
</ul>
<h3 id="heading-swagger">Swagger</h3>
<p>In order to document REST APIs in Express with Swagger, you need <a href="https://www.npmjs.com/package/swagger-jsdoc">swagger-jsdoc</a> and <a href="https://www.npmjs.com/package/swagger-ui-express">swagger-express-ui</a>. swagger-jsdoc collates and parses JSDoc-annotated documentation comments in the codebase and generates an OpenAPI specification document. swagger-ui-express uses the generated document to created a web page that renders the API documentation and test the APIs.</p>
<p>One of Swagger’s strengths lies in its support for the <a href="https://swagger.io/docs/specification/v3_0/about/">OpenAPI specification</a> which is an industry standard. Swagger is free to use, has a vibrant open source community and strong support for many programming languages and frameworks. It supports only REST APIs.</p>
<p>Its major drawback is the poor developer experience in manually writing JSDoc comments or YAML for the documentation. The process can be clumsy and developers can forget to include some annotations. Another drawback is that the JSDoc comments can interfere with reading functional code. Lastly, some developers have complained about its boring UI.</p>
<h3 id="heading-postman">Postman</h3>
<p><a href="https://www.postman.com/">Postman</a> is a cloud-based desktop API client application that allows developers and technical writers to write, test, collaborate on and publish API documentation. Unlike Swagger, it does not require deep programming experience to use most of its features. It is also not limited to REST API documentation — it can document APIs for GraphQL, websockets and gRPC.</p>
<p>Postman provides a UI to fill in details of an API documentation. The documentation process is manual and sometimes, its content can get out of sync with that of deployed applications. It is not free to use for teams and collaboration and hides the real behaviour of browser interaction with the APIs like CORS and streaming.</p>
<h3 id="heading-redoc">ReDoc</h3>
<p><a href="https://redocly.com/docs/redoc">ReDoc</a> is an open-source tool used to generate API documentation from an OpenAPI (Swagger) specification. It supports GraphQL, AsyncAPI and the OpenAPI specification and it renders a more beautiful documentation than Swagger. <a href="https://www.npmjs.com/package/redoc-express">redoc-express</a> is used to document Express REST APIs with Redoc.</p>
<p>Redoc’s major drawback is that its free community edition is presentation-only. It does not support testing the APIs. Similar to Swagger, a drawback it has is manually updating the application's OpenAPI document via a YAML specification file or JSDoc comments.</p>
<h2 id="heading-zod-to-openapi-and-scalar-for-rest-api-documentation">zod-to-openapi and Scalar for REST API Documentation</h2>
<p><a href="https://github.com/asteasolutions/zod-to-openapi">asteasolutions/zod-to-openapi</a> is a TypeScript library that generates OpenAPI specification from <a href="https://zod.dev/">zod</a> schemas. It provides typed methods which serve as guardrails for documenting API components instead of using code comments so that:</p>
<ul>
<li><p>The library methods serve as guardrails for what to document and how to document it</p>
</li>
<li><p>The documentation is consistent across the codebase</p>
</li>
<li><p>The documentation doesn't negatively affect code readability</p>
</li>
</ul>
<p>A sample snippet used to document a POST request for creating a user with zod-to-openapi is shown below:</p>
<pre><code class="language-typescript">// CreateUser and User are zod schema

registry.registerPath({
  method: "post",
  path: "/api/users",
  summary: "Create user",
  tags: ["users"],
  request: {
    body: {
      content: {
        "application/json": {
          schema: schema.CreateUser, 
        },
      },
      description: "Create user payload",
      required: true,
    },
  },
  responses: {
    201: {
      description: "User created",
      content: {
        "application/json": {
          schema: z.object({
            message: z.string(),
            data: schema.User,
          }),
        },
      },
    },
  },
});
</code></pre>
<p><a href="https://scalar.com/">Scalar</a> is a tool that generates beautiful, organized and searchable API documentation from OpenAPI documents. The documentation generated also supports testing the APIs and this makes Scalar effectively function as an API documentation generator and a lightweight API client. The image below shows a sample documentation generated by Scalar:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/56ca6e73-23a8-4245-a8d3-88c1f67b16be.svg" alt="Sample Scalar documentation UI" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h3 id="heading-how-zod-to-openapi-works-with-scalar">How zod-to-openapi Works with Scalar</h3>
<p>zod-to-openapi provides the functionality to generate an OpenAPI specification from code. Scalar uses the document generated to create a documentation web page that presents the information in the document in an organized and beautiful way that also allows for testing the APIs.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/b327b21d-c80f-472c-ba6d-6c63d212faa8.png" alt="b327b21d-c80f-472c-ba6d-6c63d212faa8" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<h2 id="heading-benefits-of-using-zod-to-openapi-and-scalar-to-create-rest-api-documentation">Benefits of Using zod-to-openapi and Scalar to Create REST API Documentation</h2>
<p>When you combine zod-to-openapi and Scalar to create REST API documentation for your Express applications, you get a myriad of benefits. Some of the benefits are explained below:</p>
<h3 id="heading-openapi-specification-support">OpenAPI Specification Support</h3>
<p>The OpenAPI specification is a format for describing REST APIs. It takes takes into consideration the important components of an API necessary for clients to use it effectively. These components include:</p>
<ul>
<li><p>Request paths, methods, headers, path parameters and query parameters,</p>
</li>
<li><p>Schemas of request and response payloads,</p>
</li>
<li><p>Authentication requirements,</p>
</li>
<li><p>Descriptions for information not accommodated by other components</p>
</li>
</ul>
<p>zod-to-openapi provides methods for all of these to be included in the documentation and it generates an OpenAPI specification-compliant document that Scalar uses to generate the documentation web page.</p>
<h3 id="heading-open-source-and-free-to-use">Open Source and Free to Use</h3>
<p>zod-to-openapi is open source and free to use. It has no plans to be unsupported or sunsetted soon because like Ruby on Rails and Laravel, the creators of the project use it in their day-to-day work.</p>
<p>Scalar is open source too. It has paid plans but the features in the paid plans are only really useful for enterprise applications. The free version supports the necessary features needed to create useful REST API documentation.</p>
<h3 id="heading-better-documentation-experience">Better Documentation Experience</h3>
<p>In terms of user experience, the union of zod-to-openapi and Scalar provides the following benefits when writing documentation with both tools:</p>
<h4 id="heading-guardrails-with-zod-to-openapi-methods">Guardrails with zod-to-openapi Methods</h4>
<p>The methods provided by zod-to-openapi serve as guardrails to ensure that developers don't omit or forget the documentation of important components of APIs. The methods also ensure that these components are documented in an OpenAPI specification-compliant manner through the typed nature of the methods' parameters.</p>
<h4 id="heading-avoid-the-clumsiness-of-comments-and-yaml-files">Avoid the Clumsiness of Comments and YAML Files</h4>
<p>With zod-to-openapi, you don't document the APIs using comments or a YAML file. You document APIs using methods from zod-to-openapi. This removes the cluttering of code with comments and the clumsiness around manually updating large YAML files of OpenAPI specification.</p>
<h4 id="heading-accuracy-and-auto-generation-of-documentation">Accuracy and Auto-generation of Documentation</h4>
<p>When you use zod-to-openapi and Scalar, your API documentation is generated automatically when the application runs. zod-to-openapi does the collation and compilation of the documented APIs, and Scalar creates a web page for it that can be hosted on an API route of the same application. You don't need to manually run CLI commands to generate the documentation.</p>
<p>Another benefit of accuracy and auto-generation is that the job of API documentation is not split between technical writer and backend developer. The documentation is in the code and this makes development faster and more seamless in terms of API documentation.</p>
<h3 id="heading-developer-friendly-ui">Developer-friendly UI</h3>
<p>While Swagger’s UI is functional, some developers consider its presentation somewhat minimal, particularly when displaying detailed endpoint descriptions. ReDoc improves on visual design but does not offer API testing features. Scalar, on the other hand, delivers a more refined and intuitive interface with greater customization options than ReDoc.</p>
<p>Beyond its design advantages, Scalar provides auto-generated code samples in multiple programming languages. This enables developers to integrate APIs more efficiently using examples tailored to their specific tech stack.</p>
<p>Scalar's UI provides a search feature that allows developers to quickly locate specific sections of the API documentation. It also includes an AI chat interface that enables users to understand how different API endpoints can help address their specific use cases. This approach is more efficient than manually reviewing the entire documentation.</p>
<p>Lastly, you can test the API endpoints from the UI. When you make authenticated API requests, the UI caches authentication tokens so that you don't have to type or paste them for subsequent requests.</p>
<h3 id="heading-markdown-support">Markdown Support</h3>
<p>zod-to-openapi and Scalar have <a href="https://scalar.com/products/api-references/markdown">Markdown support</a>. With Markdown, you can include conceptual documentation and more information about API endpoints that are not supported by the default documentation components like headers and the request body.</p>
<p>You can embed images, include tables and format text in the documentation. You can use Markdown to include notes that explain concepts related to the API.</p>
<h2 id="heading-how-to-create-the-api-documentation">How to Create the API Documentation</h2>
<p>In this section, you will create an Express CRUD API project that uses zod-to-openapi and Scalar to document its APIs. To practice along, clone the Express starter project from GitHub at <a href="https://github.com/orimdominic/freeCodeCamp-zod-to-openapi-scalar#">orimdominic/freeCodeCamp-zod-to-openapi-scalar</a>.</p>
<h3 id="heading-set-up-the-project">Set up the Project</h3>
<p>After cloning the project:</p>
<ul>
<li><p>install its dependencies using your preferred Node.js package manager</p>
</li>
<li><p>start the server using the <code>serve</code> script</p>
</li>
</ul>
<pre><code class="language-shell"># Install dependencies
npm install

# Start the application
npm run serve
</code></pre>
<p>You should see the following output on the terminal if the application runs successfully:</p>
<pre><code class="language-shell">&gt; freecodecamp-zod-to-openapi-scalar@1.0.0 serve
&gt; node --experimental-strip-types --watch src/index.ts

Listening on :3000
</code></pre>
<p>The project has two modules - Users and Pets.</p>
<p>The router configuration for each module is defined in the <code>router.ts</code> file, while the route controllers are located in the <code>controllers.ts</code> file within each module's folder under <code>src/modules</code>. The controllers do not contain business logic, they simply respond with JSON values generated by the <a href="https://fakerjs.dev/">Faker</a> library.</p>
<h3 id="heading-how-to-set-up-zod-to-openapi">How to Set Up zod-to-openapi</h3>
<p>Install <a href="https://github.com/asteasolutions/zod-to-openapi">asteasolutions/zod-to-openapi</a> using your preferred Node.js package manager. If you use npm, run the code snippet below in your terminal:</p>
<pre><code class="language-shell">npm install @asteasolutions/zod-to-openapi
</code></pre>
<p>After the installation, create a folder called <code>lib</code> (library) in the <code>src</code> folder. In the <code>lib</code> folder, create a file called <code>openapi.ts</code>. The file will house the code that sets up zod-to-openapi for collating the API documentation and generating the OpenAPI specification.</p>
<p>Copy and paste the code snippet below into <code>src/lib/openapi.ts</code>:</p>
<pre><code class="language-typescript">import z from "zod";
import {
  extendZodWithOpenApi,
  OpenApiGeneratorV31,
  OpenAPIRegistry,
} from "@asteasolutions/zod-to-openapi";

extendZodWithOpenApi(z);

export const registry = new OpenAPIRegistry();

export const bearerAuth = registry.registerComponent("securitySchemes", "bearerAuth", {
  type: "http",
  scheme: "bearer",
  bearerFormat: "JWT",
});

export function generateOpenAPIDocument() {
  const generator = new OpenApiGeneratorV3(registry.definitions);

  return generator.generateDocument({
    openapi: "3.1.0",
    info: {
      title: "Users API",
      version: "1.0.0",
      description: `Backend API documentation for users application.`,
    },
    tags: [
      {
        name: "users",
        description: "For operations carried out by admin users",
      },
    ],
    servers: [
      {
        url: "http://localhost:3000",
        description: "Local server",
      },
    ],
  });
}
</code></pre>
<blockquote>
<p>zod-to-openapi v8 requires zod v4. If you use zod v3, you should use v7.3.4 of zod-to-openapi.</p>
</blockquote>
<p><code>extendZodWithOpenApi</code> is a method provided by <code>zod-to-openapi</code> that enhances Zod schemas by adding an <code>openapi</code> method. The <code>openapi</code> method allows you to attach additional documentation to request payloads, responses, parameters, and their properties, which are then displayed in the API documentation rendered by Scalar.</p>
<p>It is important to call <code>extendZodWithOpenApi</code> before loading any files that use the <code>openapi</code> method, otherwise accessing <code>openapi</code> on Zod objects will result in errors.</p>
<p>An alternative is to use the <code>meta</code> method on zod v4 schemas for the additional documentation. For example, <code>schemaOne</code> and <code>schemaTwo</code> in the code snippet below are the same:</p>
<pre><code class="language-typescript">const schemaOne = z
  .string()
  .openapi({ description: 'Name of the user', example: 'Test' });

const schemaTwo = z
  .string()
  .meta({description: 'Name of the user', example: 'Test' });
</code></pre>
<p>The <code>meta</code> method supports all metadata information that you'd normally pass to <code>openapi</code> and will produce exactly the same results.</p>
<p>The <code>OpenAPIRegistry</code> is a utility that is used to collate API documentation which would later be passed to an OpenAPI specification generator. <code>registry</code> is created from <code>OpenAPIRegistry</code>, exported, and used to document API endpoints and components in modules where it is imported.</p>
<pre><code class="language-plaintext">export const registry = new OpenAPIRegistry();
</code></pre>
<p><code>bearerAuth</code> is a component created by the <code>registry</code> to represent JWT authentication. When <code>bearerAuth</code> is included in the documentation of an endpoint, the UI renders an input for submitting an authentication token for authenticated requests as shown in the image below.</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/2bfe72ca-a5ee-4ce5-ba5f-6ed6e1c52774.png" alt="Scalar input UI for submitting JWT" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>In the <code>registerComponent</code> method, <code>"securitySchemes"</code> registers a security scheme component. <code>"bearerAuth"</code> , the first argument of <code>registerComponent</code>, is the name given to the component and it can be changed to a name that you prefer. It appears in the top right of the authentication token input, shown in the image above. The third input to <code>registerComponent</code> is an object that defines the component.</p>
<p>When <code>generateOpenAPIDocument</code> function is executed, it collates all the registry API definitions in the project, generates the OpenAPI specification through <code>generator.generateDocument</code>, and returns the specification as JSON.</p>
<p>The <code>tags</code> property in <code>generator.generateDocument</code> organizes API endpoints into sections on the documentation UI. For example, all API endpoints with the <code>Users</code> tag in their registry definition will be placed under the <code>Users</code> section of the UI. <code>description</code> can be written in Markdown within template literals.</p>
<p>The <code>servers</code> property is a collection of the servers connected to the application. If you have multiple servers, you have the option of selecting what server to use for the base URL in the documentation UI for making API requests from it.</p>
<p>With this setup in place, when endpoints are documented with the registry, <code>generateOpenAPIDocument</code> will have an OpenAPI specification to return.</p>
<h3 id="heading-how-to-generate-the-documentation-ui-with-scalar">How to Generate the Documentation UI with Scalar</h3>
<p>In this section, you will set up Scalar and connect it to the return value of <code>generateOpenAPIDocument</code>. You will also connect Scalar with an Express route, allowing the application to serve the documentation UI at that route.</p>
<p>Scalar has an <a href="https://scalar.com/products/api-references/integrations/express">Express API reference</a> library that makes it easier for you to connect it with the OpenAPI specification and Express. Install <code>scalar/express-api-reference</code> using your preferred Node.js package manager. If you use npm, use the snippet below:</p>
<pre><code class="language-shell">npm install @scalar/express-api-reference 
</code></pre>
<p>Copy and paste the code snippet below into <code>src/app.js</code>:</p>
<pre><code class="language-typescript">import express from "express";
import router from "./router.ts";
import { generateOpenAPIDocument } from "./lib/openapi.ts";
import { apiReference } from "@scalar/express-api-reference";

const app = express();
app.use(express.json(), express.urlencoded({ extended: true }));

app.get("/", function (req, res) {
  return res.send("OK");
});

app.use("/api", router);

const apiDocJsonContent = generateOpenAPIDocument();

app.use(
  "/docs", // documentation route
  apiReference({
    content: apiDocJsonContent,
    title: "Users API",
    pageTitle: "Users API",
  }),
);

export default app;
</code></pre>
<p>In the code snippet above, <code>generateOpenAPIDocument</code> is imported from <code>src/lib/openapi.ts</code>, and <code>apiReference</code> is imported from <code>@scalar/express-api-reference</code>. When executed, <code>generateOpenAPIDocument</code> returns the OpenAPI specification, which is stored in <code>apiDocJsonContent</code> for caching to improve perfoemance.</p>
<p>A <code>GET /docs</code> route is then created, with the Scalar <code>apiReference</code> function acting as the controller. It accepts <code>apiDocJsonContent</code> and returns a web page whenever the <code>GET /docs</code> route is accessed.</p>
<p>With this setup in place, run the application using <code>npm run serve</code> and visit the documentation page at <code>http://localhost:3000/docs</code> in your browser. You should see a user interface similar to the image below:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/387698d3-ddcc-4263-8377-428399010892.png" alt="Scalar documentation starter UI" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>To view the codebase at this point, run <code>git checkout set-up-openapi-scalar</code> .</p>
<h3 id="heading-document-the-endpoints">Document the Endpoints</h3>
<p>You have set up zod-to-openapi and connected it with Scalar. You have also hooked it up with a route in the backend application. In this section, you will write code to document the endpoints in the application for generating the OpenAPI specification and rendering it on the documentation UI.</p>
<p>To document the route for creating users ( <code>POST /api/users</code> ), in <code>src/modules/users/router.ts</code> , import <code>registry</code>, the schemas and zod using the snippet below:</p>
<pre><code class="language-typescript">import z from "zod";
import { registry } from "../../lib/openapi.ts";
import { 
    UserSchema, 
    UserListItemSchema,
    UpdateUserSchema, 
    CreateUserSchema, 
} from "./types.ts";
</code></pre>
<p>Copy and paste the code below above the create user route to document the create user endpoint:</p>
<pre><code class="language-typescript">registry.registerPath({
  method: "post",
  path: "/api/users",
  summary: "Create user",
  tags: ["users"],
  request: {
    body: {
      content: {
        "application/json": {
          schema: CreateUserSchema,
        },
      },
      description: "Create user payload",
      required: true,
    },
  },
  responses: {
    201: {
      description: "User created",
      content: {
        "application/json": {
          schema: z.object({
            message: z.string().openapi({ example: "User created" }),
            data: UserSchema,
          }),
        },
      },
    },
  },
});
</code></pre>
<p>Visit the documentation page and you will find see a web page similar to the image below:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/22e0f15f-a7ee-4806-ab86-cfe922a3feda.png" alt="Scalar documentation UI for the create user route" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The UI result of some of the input fields of <code>registry.registerPath</code> have been labelled in the image above. The description in the API endpoint is italicised because its value is Markdown in a template string.</p>
<p>By registering the route path for creating users with <code>registry.registerPath</code> and filling its values, you added the documentation of the route to the registry definitions and that makes it included in the OpenAPI specification.</p>
<p>To test the endpoint from the documentation UI:</p>
<ul>
<li><p>click the <em>Test Request</em> button</p>
</li>
<li><p>fill in the payload in the dialog that appears and</p>
</li>
<li><p>click the <em>Send</em> button</p>
</li>
</ul>
<p>To document the <code>get</code> user by <code>id</code> route (<code>GET /api/users/:id</code> ), import <code>bearerAuth</code> from <code>src/lib/openapi.ts</code>, copy the code snippet below and paste it above the get user by id route definition.</p>
<pre><code class="language-typescript">registry.registerPath({
  method: "get",
  path: "/api/users/{userId}",
  summary: "Get user details by id",
  tags: ["Users"],
  security: [{ [bearerAuth.name]: [] }],
  request: {
    params: z.object({ userId: z.int() }),
  },
  responses: {
    200: {
      description: "User retrieved",
      content: { "application/json": { schema: UserSchema } },
    },
  },
});
</code></pre>
<p>When the <code>request.params</code> field is defined using a Zod object, it generates an input UI on the documentation web page that enables users to provide values for path parameters such as <code>userId</code>, highlighted in the image below:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/66e28b713f978a0e2cd2b763/ff4db093-580b-47eb-bd91-2216966566c0.png" alt="Request path parameter from registry definition on Scalar" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p>The complete code for the documentation of all endpoints in this section can be accessed when you check out the <code>complete-project</code> branch by running <code>git checkout complete-project</code> in your terminal. It contains documentation for the endpoint for uploading user photo, which demonstrates how to document endpoints that accept file uploads.</p>
<h2 id="heading-how-to-use-scalar-with-nestjs">How to Use Scalar with NestJS</h2>
<p>Scalar has a library that integrates with NestJS. You can use supply the Swagger document created by <a href="https://docs.nestjs.com/openapi/introduction">swagger/nestjs</a> to the <a href="https://scalar.com/products/api-references/integrations/nestjs">Scalar NestJS integration library</a> to generate the Scalar documentation UI.</p>
<p>In root folder of your NestJS project, install the Scalar NestJS integration library:</p>
<pre><code class="language-shell">npm install @scalar/nestjs-api-reference
</code></pre>
<p>Update the <code>main.ts</code> file of your NestJS project with the code snippet below:</p>
<pre><code class="language-typescript">import { NestFactory } from '@nestjs/core';
import { apiReference } from '@scalar/nestjs-api-reference';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const options = new DocumentBuilder()
    .setTitle('Cats example')
    .setDescription('The cats API description')
    .setVersion('1.0')
    .addTag('cats')
    .addBearerAuth()
    .build();

  const openApiSpecification = SwaggerModule.createDocument(app, options);
  
  // integrate the documentation with NestJS
  app.use(
    '/api/docs', // documentation route
    apiReference({
      content: openApiSpecification,
    }),
  )

  await app.listen(3000);
  console.log(`Application is running on: ${await app.getUrl()}`);
}

bootstrap();
</code></pre>
<p>With this setup in place, you can visit the <code>/api/docs</code> route in your browser to view the Scalar documentation for your NestJS application.</p>
<h2 id="heading-how-to-resolve-content-security-policy-csp-errors-when-used-with-helmet">How to Resolve Content Security Policy (CSP) Errors When Used with Helmet</h2>
<p>If you use <a href="https://www.npmjs.com/package/helmet">Helmet</a> in your Express or NestJS project, you will encounter <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP">CSP</a> errors when you try to render the Scalar documentation UI. To resolve the errors, update the Helmet CSP configuration in your code to have the value of the object in the code snippet below:</p>
<pre><code class="language-typescript">{
    directives: {
      defaultSrc: [`'self'`],
      styleSrc: [`'self'`, `'unsafe-inline'`],
      imgSrc: [`'self'`, 'data:', 'validator.swagger.io'],
      scriptSrc: ['self', 'https:', 'unsafe-inline'],
    },
  }
</code></pre>
<h2 id="heading-absence-of-asyncapi-documentation-feature">Absence of AsyncAPI Documentation Feature</h2>
<p>At the time of writing, Scalar does not fully support rendering AsyncAPI specifications for event-driven architecture APIs, although it is currently under development. You can track the progress of its development through the GitHub issue linked in the documentation to stay informed about its release.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>You have learned about zod-to-openapi and how it makes it easier for you to generate an OpenAPI specification for your REST APIs than writing comments or large YAML files. You also learned how to use the specification document generated to render a beautiful API documentation UI which also functions as a lightweight API client. Endeavour to implement it in your projects that need a documentation uplift.</p>
<p>Feel free to <a href="https://www.linkedin.com/in/orimdominicadah/">connect with me on LinkedIn</a> for questions or clarifications. Thank you for reading this far and I hope this helps you achieve what you intended to achieve. Don’t hesitate to share this article if you feel that it would help someone else out there. Cheers!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Documentation as a Marketing Tool ]]>
                </title>
                <description>
                    <![CDATA[ I was recently moved to the marketing team at my company, and that shift has made me reflect more deeply on the role documentation plays in our go-to-market strategy. Before this move, we've had sever ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-documentation-as-a-marketing-tool/</link>
                <guid isPermaLink="false">69989fd0a20b74e093ce4fcb</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Technical writing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ marketing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Onyeanuna Prince ]]>
                </dc:creator>
                <pubDate>Fri, 20 Feb 2026 17:54:24 +0000</pubDate>
                <media:content url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/5e1e335a7a1d3fcc59028c64/2af093b1-f1aa-42cc-b33a-b842911affcd.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I was recently moved to the marketing team at my company, and that shift has made me reflect more deeply on the role documentation plays in our go-to-market strategy.</p>
<p>Before this move, we've had several product releases, and one requirement stayed constant across all of them: the documentation had to be ready at the time of release. This wasn’t because the product was unintuitive or unusable without docs. It was because the documentation was an integral part of the product experience. A release simply wasn’t considered complete without it.</p>
<p>At a glance, this pattern can be dismissed as operational hygiene. After all, good teams ship docs alongside code. But when you look closer, it points to something more fundamental about how users actually experience products today.</p>
<p>For many products, especially developer-facing ones, documentation is often the first real interaction users have with the product. Before they sign up, before they deploy anything, and sometimes even before they talk to sales, they read the docs. This is where they assess whether the product does what it claims, whether it fits their use case, and whether it is worth investing time and effort into.</p>
<p>In practice, documentation often carries more weight than landing pages or launch blogs. Marketing content may introduce the promise of the product, but documentation is where that promise is tested. It turns positioning into reality by showing how things actually work, what trade-offs exist, and how quickly a user can succeed.</p>
<p>Seen through this lens, documentation is not just a supporting artifact but a marketing tool in its own right. It communicates product value, builds trust at the moment of highest intent, and plays a direct role in adoption.</p>
<p>In this article, I want to unpack why documentation functions this way, and why teams should start treating it as a first-class part of their go-to-market strategy rather than an afterthought.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a href="#heading-the-role-of-documentation-in-a-users-journey">The Role of Documentation in a User's Journey</a></p>
</li>
<li><p><a href="#heading-how-to-build-trust-at-the-moment-of-highest-intent">How to Build Trust at the Moment of Highest Intent</a></p>
</li>
<li><p><a href="#heading-so-what-actually-builds-trust-in-documentation">So, What Actually Builds Trust in Documentation?</a></p>
</li>
<li><p><a href="#heading-documentation-and-marketing-a-partnership">Documentation and Marketing: A Partnership</a></p>
</li>
<li><p><a href="#heading-practical-implications-treating-docs-as-marketing">Practical Implications: Treating Docs as Marketing</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-the-role-of-documentation-in-a-users-journey"><strong>The Role of Documentation in a User's Journey</strong></h2>
<p>The customer journey does not begin when someone clicks “Buy now” or "Start free trial."</p>
<p>Long before that moment, users are already forming opinions about whether a product is credible, usable, and worth their time. In traditional marketing models, this early phase is described as awareness and evaluation. But for technical products, that evaluation phase looks very different from what classic marketing funnels suggest.</p>
<p>Instead of relying primarily on demos, sales conversations, or brand messaging, technical buyers tend to self-educate. Research from <a href="https://www.gartner.com/en/newsroom/press-releases/2025-06-25-gartner-sales-survey-finds-61-percent-of-b2b-buyers-prefer-a-rep-free-buying-experience">Gartner shows that modern B2B buyers</a> spend a majority of their decision-making process researching independently before ever speaking to sales, and this behavior is even more pronounced among technical audiences who prefer primary sources over promotional material.</p>
<p>For developer tools, APIs, and infrastructure products, documentation becomes one of those primary sources. Users move from high-level marketing pages into documentation to answer concrete questions such as how the product works, what it integrates with, what assumptions it makes, and what it will realistically take to adopt. This transition from marketing to documentation is a natural progression in the evaluation process.</p>
<p>In the book <a href="https://www.splunk.com/en_us/blog/splunklife/the-product-is-docs.html">The Product Is Docs</a>, the Splunk documentation team describes this transition as needing to be “seamless, cohesive, and logical.” Their point, much more than consistency in tone or branding, is about continuity of understanding.</p>
<p>When users move from marketing content into documentation, they are testing whether the product narrative holds up under scrutiny. If the documentation is incomplete, confusing, or disconnected from what marketing promised, confidence drops quickly, not only in the docs, but in the product itself.</p>
<p>This idea aligns closely with broader research on content-driven buying behavior. Studies on developer experience consistently show that documentation quality is a key factor in product evaluation and adoption. A report by <a href="https://www.slashdata.co/post/software-development-challenges-are-technical-and-strategic">SlashData</a> found that poor or unclear documentation is one of the top reasons developers abandon tools during evaluation, even when the underlying technology is sound.</p>
<p>What this highlights is that documentation does not sit at the end of the user journey, after a purchase has been made. It sits directly in the middle of the decision-making process. It acts as the bridge between curiosity and commitment. Marketing may introduce the problem space and position the solution, but documentation is where users validate whether the solution is real, usable, and aligned with their needs.</p>
<p>The Splunk team refers to this as creating an “integrated content experience,” where marketing and documentation work together to guide users from initial awareness through evaluation, purchase, and successful implementation.</p>
<h2 id="heading-how-to-build-trust-at-the-moment-of-highest-intent"><strong>How to Build Trust at the Moment of Highest Intent</strong></h2>
<p>When users arrive at your documentation, they’re no longer casually exploring. They’re actively evaluating whether your product fits their needs and whether it’s worth committing time, effort, or money to. This is what makes documentation a uniquely high-intent touchpoint in the user journey.</p>
<p>In marketing terms, high-intent moments are rare and valuable. They occur when users are close to making a decision and are seeking confirmation.</p>
<p>For technical products, documentation is often the primary surface where this confirmation happens. Research from <a href="https://business.google.com/uk/think/consumer-insights/the-consumer-decision-making-process/">Google on decision-making behavior</a> shows that users rely heavily on “trust signals” at moments of intent, and for technical buyers, accuracy and depth of information matter more than persuasive language.</p>
<p>This is why documentation quality has an outsized impact on outcomes. When users encounter clear and practical documentation during evaluation, confidence increases. When they encounter gaps, inconsistencies, or ambiguity, doubt sets in immediately. Unlike marketing content, documentation doesn’t get the benefit of abstraction. It’s expected to be precise and complete.</p>
<p>Documentation is part of a continuous guide that “holds a customer’s hand” from evaluation through purchase and into successful usage. This framing is important because it highlights that trust isn’t built once and forgotten. It’s maintained across stages. Documentation inherits the trust marketing creates, but it must earn its own by demonstrating technical credibility and practical value.</p>
<p>This is the point where many products fail because marketing successfully drives interest, but documentation breaks the trust loop by failing to support the claims made earlier. When that happens, users don’t just lose confidence in the docs but also in the product and, by extension, the company behind it.</p>
<h2 id="heading-so-what-actually-builds-trust-in-documentation"><strong>So, What Actually Builds Trust in Documentation?</strong></h2>
<p>Trust in documentation isn’t subjective. It’s shaped by specific, observable qualities that users quickly pick up on during evaluation.</p>
<p>Accuracy is the foundation. When examples work as described, and behavior matches documentation, users feel safe moving forward. When it doesn’t, you have a problem. Studies on <a href="https://www.archbee.com/blog/invisible-roadblock-poor-documentation-and-how-to-break-through">developer experience</a> consistently rank inaccurate documentation as one of the fastest ways to lose adoption, even when the underlying product is powerful.</p>
<p>Completeness is a signal of maturity. Documentation that covers core workflows, edge cases, and limitations tells users that the product has been thought through. Gaps, missing sections, or “coming soon” pages suggest instability or unfinished work. For evaluators, this raises red flags about long-term viability.</p>
<p>Another point is honesty, which plays an equally important role. Strong documentation doesn’t hide constraints or trade-offs. Instead, it acknowledges them clearly. Research in trust psychology shows that transparency, even about limitations, increases perceived credibility because it reduces uncertainty and surprises later.</p>
<p>Also, more recently updated docs reflect better on team health. Updated documentation signals active maintenance and ongoing investment. On the other hand, outdated docs suggest abandonment or stagnation. For technical buyers, this is often interpreted as a warning sign about support and future development.</p>
<p>Finally, usability determines whether trust can even form. Documentation that is difficult to navigate, poorly structured, or even hard to search fails before its content is evaluated. <a href="https://www.nngroup.com/articles/information-foraging/">Nielsen Norman Group’s research on information-seeking behavior</a> shows that users abandon content quickly when they cannot find answers with minimal effort, regardless of quality.</p>
<p>Together, these factors shape how users perceive not just the documentation, but the product and organization behind it.</p>
<h2 id="heading-documentation-and-marketing-a-partnership">Documentation and Marketing: A Partnership</h2>
<p>In the book The Product is Docs, the authors observe that documentation teams and marketing teams "have more in common than you might think." Both are responsible for communicating product value to audiences, both create content that influences buying decisions, and both play crucial roles in the customer journey.</p>
<p>Yet these teams often operate separately, thereby creating disconnected experiences for users.</p>
<p>Marketing promises capabilities without understanding technical constraints, while documentation focuses on implementation details without connecting to broader use cases or business value.</p>
<p>The result of this is a jarring transition from marketing to product that undermines both efforts.</p>
<h3 id="heading-so-how-can-marketing-help-documentation">So, how can marketing help documentation?</h3>
<p>Marketing teams bring a valuable perspective to documentation:</p>
<ul>
<li><p><strong>Customer insights</strong>: Marketing interacts directly with prospects and customers through demos, events, and demand generation. These interactions surface real questions and pain points that documentation should address.</p>
</li>
<li><p><strong>Competitive intelligence</strong>: Understanding how competitors document their products can reveal opportunities for differentiation or improvement.</p>
</li>
<li><p><strong>Strategic priorities</strong>: Knowing which features marketing will emphasize helps documentation teams focus their effort where it will have the most impact.</p>
</li>
<li><p><strong>Target audience definition</strong>: Marketing's customer research and personas can inform documentation structure and examples.</p>
</li>
</ul>
<h3 id="heading-andhow-can-good-documentation-help-marketing">And...how can good documentation help marketing?</h3>
<p>Documentation teams bring equally valuable assets to the partnership:</p>
<ul>
<li><p><strong>Technical accuracy</strong>: Documentation teams can review marketing materials for technical correctness and help refine messaging to be both compelling and accurate.</p>
</li>
<li><p><strong>Content leverage</strong>: Well-written documentation can be adapted into blog posts, white papers, and other marketing content.</p>
</li>
<li><p><strong>User feedback</strong>: Documentation teams often receive direct feedback from users about what's confusing or what features resonate most.</p>
</li>
<li><p><strong>Writing expertise</strong>: Technical writers can help develop clearer, more effective marketing content.</p>
</li>
</ul>
<p>The Splunk team emphasizes that this collaboration should span the entire release cycle: "Before you write" (to align on priorities and naming), "As you write" (to validate approaches), and "After you write" (to ensure consistency and quality).</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770917891627/176c277b-2ac7-4f2a-bcdd-c236c98f06bc.png" alt="Release cycle" style="display:block;margin:0 auto" width="600" height="400" loading="lazy">

<p><strong>Figure 1:</strong> <em>Embedding docs in the release cycle</em></p>
<h2 id="heading-practical-implications-treating-docs-as-marketing"><strong>Practical Implications: Treating Docs as Marketing</strong></h2>
<p>If documentation is indeed a marketing tool, what changes in how we approach it?</p>
<h3 id="heading-1-documentation-should-ship-with-product-launches">1. Documentation should ship with product launches</h3>
<p>This is where my own experience began. Documentation can't be an afterthought that ships weeks after launch. If docs are part of how users evaluate and adopt the product, they need to be ready when the product is. This means involving documentation teams early in the development process, not at the end.</p>
<p>As the Splunk team notes in their discussion of Agile development: "There is no definition of ‘done’ without docs. Customer documentation is part of the working software." This principle should extend to marketing launches as well.</p>
<h3 id="heading-2-invest-in-documentation-quality-and-discoverability">2. Invest in documentation quality and discoverability</h3>
<p>If documentation influences buying decisions, it deserves the same attention to quality and user experience as marketing websites. This means:</p>
<ul>
<li><p>Professional design and navigation</p>
</li>
<li><p>Fast search functionality</p>
</li>
<li><p>Clear information architecture</p>
</li>
<li><p>Mobile-friendly formatting</p>
</li>
<li><p>SEO optimization for relevant queries</p>
</li>
</ul>
<p>Too often, documentation sites are neglected from a UX perspective while marketing pages receive constant refinement. This sends a message about priorities that users notice.</p>
<h3 id="heading-3-create-an-integrated-content-experience">3. Create an integrated content experience</h3>
<p>The transition from marketing to documentation should feel natural. This requires:</p>
<ul>
<li><p><strong>Consistent terminology</strong>: Features should be named the same way in marketing materials and documentation.</p>
</li>
<li><p><strong>Aligned narratives</strong>: The use cases highlighted in marketing should have detailed implementation guides in the documentation.</p>
</li>
<li><p><strong>Cross-linking</strong>: Marketing pages should link directly to relevant documentation sections, and vice versa.</p>
</li>
<li><p><strong>Shared success metrics</strong>: Both teams should care about the same outcomes –&nbsp;not just awareness or signups, but successful implementation and adoption.</p>
</li>
</ul>
<p>The Splunk team describes this as helping customers avoid feeling "disoriented or, worse, feel misled." Good documentation delivers on marketing's promises with specifics on how to achieve the outcomes that were advertised.</p>
<h3 id="heading-4-measure-documentation-impact-on-conversion">4. Measure documentation impact on conversion</h3>
<p>If documentation is part of the marketing funnel, it should be measured as such. As a documentation team, you should track metrics like:</p>
<ul>
<li><p>Documentation page views from prospective customers</p>
</li>
<li><p>Time spent in docs before conversion</p>
</li>
<li><p>Most-viewed pages during evaluation periods</p>
</li>
<li><p>Correlation between documentation engagement and trial-to-paid conversion</p>
</li>
<li><p>Customer feedback on documentation quality during the buying process</p>
</li>
</ul>
<p>These metrics help demonstrate documentation's business impact and justify investment in quality improvements.</p>
<blockquote>
<p>If you're curious about examples of docs that embody these strategies, then you might want to check out&nbsp;<a href="https://www.twilio.com/docs">Twilio</a>,&nbsp;<a href="https://docs.stripe.com/">Stripe</a>, or, as mentioned earlier, the&nbsp;<a href="https://docs.splunk.com/Documentation">Splunk</a>&nbsp;docs.</p>
</blockquote>
<h3 id="heading-why-does-all-this-matter-now">Why does all this matter now?</h3>
<p>The role of documentation in driving adoption has always been important, but several trends are making it more critical:</p>
<p>First, as more companies adopt PLG strategies, the product experience, including documentation, becomes the primary sales vehicle. There's no sales team to answer questions or guide implementation. The docs must do that work.</p>
<p>Second, technical buyers increasingly want to evaluate products independently before engaging with sales. Documentation is often their primary evaluation tool.</p>
<p>We’re also seeing shorter sales cycles. When buying cycles compress, there's less time for demos and sales engineering. Documentation needs to answer questions immediately.</p>
<p>And finally, for developer tools and infrastructure products, individual contributors often drive adoption from the bottom up. These users rely heavily on documentation for their evaluation process.</p>
<p>In this environment, treating documentation as an operational necessity rather than a strategic asset is a competitive disadvantage. Companies that recognize documentation as a core part of their go-to-market strategy and invest accordingly see better conversion rates and stronger customer relationships.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Documentation is not just a post-purchase support resource. It's an active participant in the customer journey, influencing buying decisions and driving adoption.</p>
<p>For technical products, especially, documentation often carries more weight than traditional marketing materials.</p>
<p>This doesn't mean documentation should become marketing copy. It means recognizing that documentation performs a marketing function such as communicating value and building credibility, even while maintaining its technical accuracy and practical focus.</p>
<p>As the Splunk documentation team wisely notes, the goal is to create an integrated content experience where marketing and documentation work together to guide users from initial interest through successful implementation.</p>
<p>So, the requirement that documentation be ready at release time wasn't just operational hygiene. It was recognition that our product wasn't truly ready for market until users could both evaluate it and successfully use it. That's what makes documentation a marketing tool, not because it makes exaggerated claims, but because it delivers on the promise that marketing makes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ System Architecture Documentation Best Practices and Tools ]]>
                </title>
                <description>
                    <![CDATA[ Imagine being asked to give UX feedback on a system workflow document and realizing you can’t understand a word of it. That’s exactly what happened to me. As an IT support officer, I can put myself in the perspective of a user and identify friction p... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/system-architecture-documentation-best-practices-and-tools/</link>
                <guid isPermaLink="false">691484910576aea108fc08d8</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Collaboration ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ifeoma Udu ]]>
                </dc:creator>
                <pubDate>Wed, 12 Nov 2025 12:58:57 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762950321590/b67b93ef-de20-430b-a160-13631259c1d5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine being asked to give UX feedback on a system workflow document and realizing you can’t understand a word of it. That’s exactly what happened to me.</p>
<p>As an IT support officer, I can put myself in the perspective of a user and identify friction points, but this document had no visuals, no simplified explanations, just walls of backend jargon: <em>service mesh, container orchestration, async queues, REST APIs… you name it.</em></p>
<p>I realized quickly: if someone like me struggles to understand this, so will PMs, frontend devs, new hires, and even other IT staff.</p>
<p>Here’s a practical guide for creating system architecture documentation that anyone on your team can read and use:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-show-the-system-from-different-angles">Step 1: Show the System from Different Angles</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-make-diagrams-the-star">Step 2: Make Diagrams the Star</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-translate-tech-into-user-relevant-outcomes">Step 3: Translate Tech Into User-Relevant Outcomes</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-make-communication-clear">Step 4: Make Communication Clear</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-keep-it-simple-and-consistent">Step 5: Keep it Simple and Consistent</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-system-architecture-documentation-tools-for-teams">System Architecture Documentation Tools for Teams</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-step-1-show-the-system-from-different-angles"><strong>Step 1: Show the System from Different Angles</strong></h2>
<p>A good architecture doc isn’t just a list of tech terms. Think about who is reading it:</p>
<p><strong>A. Conceptual View (PM/UX/business folks)</strong></p>
<ul>
<li><p>What the system does for the user.</p>
</li>
<li><p>Example: <em>“User Authentication System,” “Checkout Service”</em></p>
</li>
<li><p>Focus on user value and business goals.</p>
</li>
</ul>
<p><strong>B. Component View (frontend developers/IT staff)</strong></p>
<ul>
<li><p>How the parts interact.</p>
</li>
<li><p>Example: <em>“Web App calls API Gateway → Microservice → Database”</em></p>
</li>
<li><p>Focus on data flow and system boundaries.</p>
</li>
</ul>
<p><strong>C.   Operational View (backend/DevOps)</strong></p>
<ul>
<li><p>Where the system runs and how.</p>
</li>
<li><p>Example: <em>servers, databases, cloud setup, scaling.</em></p>
</li>
<li><p>Focus on infrastructure and deployment.</p>
</li>
</ul>
<p>This way, everyone can find what’s relevant to their role without getting lost in technical weeds.</p>
<h2 id="heading-step-2-make-diagrams-the-star"><strong>Step 2: Make Diagrams the Star</strong></h2>
<p>Words alone don’t cut it. Diagrams help people visualize the system, especially if they’re not experts.</p>
<p><strong>Types of Diagrams to Include</strong></p>
<ul>
<li><p><strong>System Context Diagram:</strong> Shows the system and its external dependencies. UX/PM/IT staff can see how it touches users and other systems.</p>
</li>
<li><p><strong>Container Diagram:</strong> Shows main boundaries like <em>“Web App,” “Auth API,” “Database.”</em> Frontend and backend teams benefit.</p>
</li>
<li><p><strong>UML/Component Diagram:</strong> Shows internal structure or interactions. Mostly backend focus, but helps everyone understand flow.</p>
</li>
</ul>
<p><strong>Tip:</strong> Even a simple flowchart drawn in PowerPoint, Figma, or by hand is better than none. Clarity matters more than perfection.</p>
<p>Diagrams help:</p>
<ul>
<li><p>UX sees user impact.</p>
</li>
<li><p>Frontend knows which services to hook up.</p>
</li>
<li><p>Backend sees infrastructure and interactions.</p>
</li>
<li><p>Everyone shares the same mental picture.</p>
</li>
</ul>
<h3 id="heading-example-1-system-context-diagram">Example 1: System Context Diagram</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762421963002/ab9f11d4-e30f-4e4a-9510-55b4b3f5e8ad.jpeg" alt="Flowchart illustrating an end user visiting a web app, which processes payments via Stripe API and sends emails through SendGrid using webhooks." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This diagram illustrates who uses the system (a person on the web) and which external services it depends on, like Stripe for payments and SendGrid for emails. It doesn't show the internal workings of the system, just what it connects to.</p>
<h3 id="heading-example-2-container-diagram">Example 2: Container Diagram</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762612172310/1ef1b7e9-0441-4d34-b136-2283ec0b4c56.jpeg" alt="Flowchart depicting a web application architecture. The sequence starts with a web browser, leading to a frontend app, then to an API gateway. The gateway splits into two paths: one leads to an Auth Service connected to a User Database, and the other to an Order Service connected to an Orders Database." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>This diagram illustrates the main components of the system: the Web App, which is the user interface; the Auth API, responsible for handling login and security; and the User Database, where user profiles are stored. The arrows indicate how these components interact with each other.</p>
<p><strong>Practical Tip: Tools to Create Clear Architecture Docs.</strong></p>
<h2 id="heading-step-3-translate-tech-into-user-relevant-outcomes"><strong>Step 3: Translate Tech Into User-Relevant Outcomes</strong></h2>
<p>System architecture goes beyond databases and queues, focusing on making the product fast, reliable, and secure for users. Link technical requirements to outcomes everyone can understand:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Requirement</strong></td><td>❌ <strong>Technical Jargon</strong></td><td>✅ <strong>User Outcome</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Scalability</td><td>Kubernetes for container orchestration</td><td>Can handle 10x daily users without slowdowns.</td></tr>
<tr>
<td>Performance</td><td>CDN + caching</td><td>Pages load in under 500ms, no “loading” screens.</td></tr>
<tr>
<td>Security</td><td>TLS 1.3 for data transfer</td><td>User data is safe; only authorized systems access PII(Personally Identifiable Information)<strong>.</strong></td></tr>
</tbody>
</table>
</div><p>Even a person with basic UX awareness can see why tech decisions matter.</p>
<h2 id="heading-step-4-make-communication-clear"><strong>Step 4: Make Communication Clear</strong></h2>
<p>One major source of confusion is how different parts of the system talk to each other. Spell it out:</p>
<p>a) Frontend ↔ Backend: Clearly explain how your frontend connects to the backend.</p>
<p>Example: <em>“The website sends login requests to the Auth API.”</em></p>
<p>b) Backend ↔ Backend: Explain whether services communicate with each other instantly (synchronous) or through background tasks like message queues (asynchronous). This helps the team understand why some actions feel instant to users, while others take time.</p>
<p>Even non-backend readers can follow the flow and understand how it impacts the product.</p>
<h2 id="heading-step-5-keep-it-simple-and-consistent"><strong>Step 5: Keep it Simple and Consistent</strong></h2>
<ul>
<li><p>Use headings, bullet points, and a table of contents. Don’t write a novel.</p>
</li>
<li><p>Keep names consistent: <em>“User Service”</em> in diagrams should match text labels.</p>
</li>
<li><p>Explain the “why” behind major decisions:</p>
</li>
</ul>
<p><em>“We chose a NoSQL DB for User Profiles because it requires fast read/write for non-relational data.”</em></p>
<p>Consistency and simplicity make the doc useful to everyone, not just backend experts.</p>
<h2 id="heading-system-architecture-documentation-tools-for-teams"><strong>System Architecture Documentation Tools for Teams</strong></h2>
<p>Great architecture documentation lives where your team already works and uses tools that are easy to update, share, and understand. Below are the common types of tools teams use, grouped by purpose.</p>
<h3 id="heading-documentation-platforms-where-you-write-the-full-doc">Documentation Platforms (Where You Write the Full Doc)</h3>
<p>You can use these tools to combine text, diagrams, and structure a document.</p>
<p><strong>Google Docs</strong><br>Simple, familiar, and collaborative. Supports real-time comments, edit history, and easy sharing. Perfect if your team already uses Gmail or Drive. Just paste diagrams as images.</p>
<p><strong>Confluence</strong><br>Common in larger companies. Integrates with Jira, supports page templates, and lets you embed diagrams. Good for structured knowledge bases.</p>
<p><strong>Notion</strong><br>Flexible workspace for small teams. Mix docs, tasks, and diagrams in one place. Great if your team uses Notion for other work.</p>
<p><strong>GitHub/GitLab Wikis (with Markdown)</strong><br>Ideal for engineering-heavy teams. Docs live next to your code, and you can include diagrams using simple code (like Mermaid). Changes are tracked like code.</p>
<blockquote>
<p><strong>Start with Google Docs</strong> if you’re unsure. A living doc people actually read is better than a “perfect” one no one opens.</p>
</blockquote>
<h3 id="heading-diagramming-tools-where-you-create-visuals"><strong>Diagramming Tools (Where You Create Visuals)</strong></h3>
<p>These help you draw the architecture diagrams you’ll add to your documentation platform.</p>
<p><strong>Draw.io</strong><br>Free, browser-based, and drag-and-drop simple. No sign-up needed. Exports clean PNG/SVG files you can paste into Docs or Confluence. Great for C4-style diagrams (System Context, Container, and so on).</p>
<p><strong>Figma</strong><br>If your team already uses Figma for design, you can create architecture diagrams using basic shapes and arrows. Real-time commenting makes feedback easy. Just export as PNG for Docs.</p>
<p><strong>Mermaid (Diagrams as Code)</strong><br>Write simple text like <code>User --&gt; Web App</code>, and it becomes a diagram. Works in GitHub, GitLab, and tools like Obsidian. Use the <a target="_blank" href="https://mermaid.live/">Mermaid Live Editor</a> to design, then download and paste into Google Docs.</p>
<h4 id="heading-a-key-insight-from-practicing-architects"><strong>A Key Insight from Practicing Architects.</strong></h4>
<p>Avoid tools that <strong>only produce static images</strong> (like PowerPoint, Canva, or basic whiteboards) for anything beyond quick sketches. If the same service appears in three diagrams and you rename it, you’ll have to update all three manually, leading to outdated and inconsistent docs.</p>
<h3 id="heading-how-they-work-together"><strong>How They Work Together</strong></h3>
<ol>
<li><p>Write your doc in Google Docs (or your team’s existing platform).</p>
</li>
<li><p>Create diagrams in Draw.io or Figma (or try Mermaid if you’re curious).</p>
</li>
<li><p>Paste the diagram into your doc, add alt text, and explain what it shows in plain language.</p>
</li>
</ol>
<p>This combo gives you accessibility, collaboration, and maintainability without overwhelming you or your team.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>You don’t need to be a senior engineer to write great architecture docs. You just need clarity, empathy, and the willingness to explain “why.”</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Documentation that Helps Your Tech Community Grow ]]>
                </title>
                <description>
                    <![CDATA[ Good documentation is the backbone of a supported and empowered community. From the moment someone new joins and finds a clear guide to get started, to the experienced member who can quickly find a process, well-organized information saves everyone t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-documentation-that-helps-your-tech-community-grow/</link>
                <guid isPermaLink="false">68cde1bb85ffecd5a404fc5f</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ developer relations ]]>
                    </category>
                
                    <category>
                        <![CDATA[ community ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oladeji Oluwaseun ]]>
                </dc:creator>
                <pubDate>Fri, 19 Sep 2025 23:05:31 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1758323106904/8b5b31a1-1392-4376-b7d5-126909eb944f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Good documentation is the backbone of a supported and empowered community. From the moment someone new joins and finds a clear guide to get started, to the experienced member who can quickly find a process, well-organized information saves everyone time and frustration.</p>
<p>Most community managers spend hours each week answering the same questions over and over. You might find yourself repeating instructions for how to join a project, what the process for submitting an event proposal is, or who to contact for a specific problem because "everyone just knows" how things work. The issue is that the information isn't easy to find or understand when your community members need it most.</p>
<p>Effective documentation is the unsung hero of a thriving community. In this tutorial, you will learn how to create documentation that genuinely serves your tech community. You will discover proven techniques for organizing information, writing clear instructions, and building systems that work for both newcomers and experienced contributors.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-why-community-documentation-often-falls-short">Why Community Documentation Often Falls Short</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-core-principles-for-effective-community-documentation">Core Principles for Effective Community Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-know-who-you're-writing-for">How to Know Who You're Writing For</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-organize-information-for-easy-access">How to Organize Information for Easy Access</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-instructions-that-people-can-actually-follow">How to Write Instructions That People Can Actually Follow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-essential-documentation-every-tech-community-needs">Essential Documentation Every Tech Community Needs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-new-member-onboarding-guide">How to Create a New Member Onboarding Guide</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-community-operating-procedures-handbook">The Community Operating Procedures Handbook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-event-planning-handbook">The Event Planning Handbook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-community-guidelines-and-behavioral-expectations-handbook">The Community Guidelines and Behavioral Expectations Handbook</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-whether-your-documentation-works">How to Test Whether Your Documentation Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-observe-how-people-actually-use-information">How to Observe How People Actually Use Information</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-ask-targeted-questions-for-improvement">How to Ask Targeted Questions for Improvement</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-monitor-community-health-indicators">How to Monitor Community Health Indicators</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-maintain-documentation-as-your-community-evolves">How to Maintain Documentation as Your Community Evolves</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-schedule-regular-review-cycles">How to Schedule Regular Review Cycles</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-systems-for-community-input">How to Create Systems for Community Input</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-documentation-updates-into-regular-workflows">How to Build Documentation Updates into Regular Workflows</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-a-culture-of-clear-communication">How to Create a Culture of Clear Communication</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-model-excellent-communication-practices">How to Model Excellent Communication Practices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-clarity-into-decision-making">How to Integrate Clarity into Decision-Making</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-recognize-clear-communication">How to Recognize Clear Communication</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To get the most from this tutorial, you should have:</p>
<ul>
<li><p>Experience participating in or managing tech communities.</p>
</li>
<li><p>Responsibility for creating processes or guidelines that others need to follow.</p>
</li>
<li><p>Access to community platforms like Slack, Discord, or similar communication tools.</p>
</li>
</ul>
<p>No formal writing experience is required. This guide focuses on practical approaches that work in community settings.</p>
<h2 id="heading-why-community-documentation-often-falls-short">Why Community Documentation Often Falls Short</h2>
<p>Documentation often fails because it is created for the wrong audience or stored in a way that makes it difficult to find. A common pitfall is creating documentation that is too technical or formal, using jargon that is not understood by new members. Another issue is that documentation is often a one-time effort, not a living resource. When processes or team members change, the documentation becomes outdated and unreliable, causing people to abandon it entirely.</p>
<h2 id="heading-core-principles-for-effective-community-documentation">Core Principles for Effective Community Documentation</h2>
<p>Strong community documentation is built on four key principles that make information genuinely useful rather than just comprehensive.</p>
<h3 id="heading-how-to-know-who-youre-writing-for">How to Know Who You're Writing For</h3>
<p>Different community members need different information depending on their experience level and involvement goals. Consider these main audiences:</p>
<ul>
<li><p>New members who are exploring how to participate.</p>
</li>
<li><p>Active participants looking for specific opportunities or information.</p>
</li>
<li><p>Volunteers needing clear instructions for their responsibilities.</p>
</li>
<li><p>Organizers requiring detailed procedures and decision-making guidelines.</p>
</li>
</ul>
<h2 id="heading-how-to-organize-information-for-easy-access">How to Organize Information for Easy Access</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757643794273/0a4f786d-fd75-428e-a0f2-06af3f1265e4.png" alt="Organize Information For Easy Access" width="1515" height="568" loading="lazy"></p>
<p>The way you structure information is just as important as the information itself. Good documentation anticipates a user's needs, allowing them to find what they are looking for without digging through endless pages.</p>
<p>A well-organized documentation hub should mirror your community's journey. Start with high-level, introductory information and then branch out into more specific, detailed guides. For example, a newcomer should see a clear pathway to finding a welcome guide, while an experienced volunteer should be able to jump directly to a detailed event checklist.</p>
<p>Think about using a central location that is easy to access, such as a dedicated channel, a pinned post in your community platform, or a simple, single-page website. Use subheadings and bullet points to break down long sections of text, making the content scannable and digestible.</p>
<h2 id="heading-how-to-write-instructions-that-people-can-actually-follow">How to Write Instructions That People Can Actually Follow</h2>
<p>Clear instructions are the bedrock of effective documentation. When you write a guide, imagine you are sitting with a new volunteer, talking them through a task step-by-step. Use active voice and simple, direct language. For example, instead of writing "The event registration form should be created," write "Create the event registration form."</p>
<p>Use numbered lists to guide readers through a process in a logical order. You can use screenshots and diagrams to illustrate a point, but make sure they are clear and easy to understand. For instance, a screenshot of a community's Standard Operating Procedure (SOP) document can help a new team member visualize their tasks.</p>
<h2 id="heading-essential-documentation-every-tech-community-needs">Essential Documentation Every Tech Community Needs</h2>
<p>Different types of documentation serve different purposes in community management. Here are the most important ones to prioritize.</p>
<h3 id="heading-how-to-create-a-new-member-onboarding-guide">How to Create a New Member Onboarding Guide</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757638101839/8af95b79-51a9-44da-ab7b-76590b692ad5.png" alt="Image of an onboarding guide" width="839" height="706" loading="lazy"></p>
<p>Your onboarding documentation should help new members feel welcome and find their first meaningful way to participate. Effective onboarding includes:</p>
<ul>
<li><p>A welcome message explaining community values and culture.</p>
</li>
<li><p>A quick overview of how to access and use community platforms.</p>
</li>
<li><p>Immediate ways to get involved that match different comfort levels.</p>
</li>
<li><p>A community calendar highlighting upcoming opportunities.</p>
</li>
<li><p>Clear contact information for getting help.</p>
</li>
</ul>
<h3 id="heading-the-community-operating-procedures-handbook">The Community Operating Procedures Handbook</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757201469213/61d37f6b-7d3d-42f2-9935-d8b37dec5be3.png" alt="Example of A Standard Operating Procedure document" width="948" height="720" loading="lazy"></p>
<p>Standard procedures ensure consistent experiences regardless of which team member handles a situation. As community management expert <a target="_blank" href="https://www.linkedin.com/in/rosemaryoneill/">Rosemary O'Neill</a> notes:</p>
<blockquote>
<p>"Clear processes are not about bureaucracy – they are about creating predictable, positive experiences that let community members focus on connection rather than confusion."</p>
</blockquote>
<p>Comprehensive community procedures should address:</p>
<ul>
<li><p><strong>Team Structure and Operations:</strong> Community mission statement and core values, team roles with clear responsibility boundaries, decision-making processes and approval workflows, communication protocols for different situations.</p>
</li>
<li><p><strong>Member Experience Management:</strong> Application review standards and timeline expectations, new member welcome sequence with multiple touchpoints, engagement strategies including regular check-ins and recognition programs, pathway documentation for members to increase involvement, feedback collection methods and response protocols, professional offboarding process for departing members.</p>
</li>
<li><p><strong>Community Building and Growth:</strong> Content creation guidelines and approval processes, partnership evaluation criteria with other organizations, volunteer recruitment strategies and management systems, leadership development opportunities and requirements.</p>
</li>
<li><p><strong>Event and Program Management:</strong> Event planning workflows from initial concept to post-event review, speaker recruitment, vetting, and coordination procedures; registration management and attendee communication templates, technical requirements and setup procedures for different event formats, post-event evaluation and improvement documentation.</p>
</li>
<li><p><strong>Community Health and Safety:</strong> Conflict resolution procedures with clear escalation paths, community guideline enforcement protocols and consequences, crisis communication plans and emergency contacts, member well-being resources and support systems.</p>
</li>
<li><p><strong>Evaluation and Improvement:</strong> Community health metrics and regular assessment schedules, member satisfaction measurement and analysis methods, growth tracking systems and reporting requirements, quarterly review processes and improvement planning.</p>
</li>
</ul>
<h3 id="heading-the-event-planning-handbook">The Event Planning Handbook</h3>
<p>Events often drive community engagement and growth. Your event documentation should enable teams to create successful experiences consistently. Organize event documentation by timeline:</p>
<ul>
<li><p><strong>6-8 weeks prior:</strong> Initial planning, venue booking, speaker outreach.</p>
</li>
<li><p><strong>4-6 weeks prior:</strong> Registration setup, marketing launch, logistics confirmation.</p>
</li>
<li><p><strong>2-4 weeks prior:</strong> Final details, volunteer coordination, attendee communication.</p>
</li>
<li><p><strong>Week of event:</strong> Setup procedures, team briefings, backup plans.</p>
</li>
<li><p><strong>Event day:</strong> Detailed checklists for setup, execution, and wrap-up.</p>
</li>
<li><p><strong>Post-event:</strong> Follow-up tasks, feedback collection, documentation updates.</p>
</li>
</ul>
<h3 id="heading-the-community-guidelines-and-behavioral-expectations-handbook">The Community Guidelines and Behavioral Expectations Handbook</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757644301107/b7fcee82-fc6b-45fe-94ce-bfcd327ee8f9.png" alt="Example of A Community Guideline" width="899" height="719" loading="lazy"></p>
<p>Community guidelines should clearly communicate expectations while reflecting your community's specific culture and values. Effective community guidelines include:</p>
<ul>
<li><p>Specific behavioral expectations with concrete examples.</p>
</li>
<li><p>Clear consequences that focus on community repair and learning.</p>
</li>
<li><p>Accessible reporting procedures for concerns or conflicts.</p>
</li>
<li><p>Resolution processes that prioritize healing and growth.</p>
</li>
<li><p>Recognition systems for positive community contributions.</p>
</li>
</ul>
<h2 id="heading-how-to-test-whether-your-documentation-works">How to Test Whether Your Documentation Works</h2>
<p>Creating documentation is only the first step. You need to verify that it actually helps people succeed in your community.</p>
<h3 id="heading-how-to-observe-how-people-actually-use-information">How to Observe How People Actually Use Information</h3>
<p>The most valuable feedback comes from watching interactions between community members and your documentation. Observation methods:</p>
<ul>
<li><p>Ask new volunteers to follow your procedures while you watch (without providing extra help).</p>
</li>
<li><p>Monitor community channels for repeated questions that suggest documentation gaps.</p>
</li>
<li><p>Track completion rates for multi-step processes.</p>
</li>
<li><p>Pay attention to member feedback about confusing or particularly helpful resources.</p>
</li>
</ul>
<h3 id="heading-how-to-ask-targeted-questions-for-improvement">How to Ask Targeted Questions for Improvement</h3>
<p>Generic feedback does not provide enough detail for meaningful improvements. Ask specific questions that reveal actual pain points. Useful feedback questions:</p>
<ul>
<li><p>"At what point did you feel unsure about what to do next?"</p>
</li>
<li><p>"What information were you looking for that you could not easily find?"</p>
</li>
<li><p>"If you were teaching this process to someone else, what would you explain differently?"</p>
</li>
<li><p>"What would have made this experience smoother or more welcoming?"</p>
</li>
</ul>
<h3 id="heading-how-to-monitor-community-health-indicators">How to Monitor Community Health Indicators</h3>
<p>Good documentation should contribute to overall community sustainability and member satisfaction. Signs that documentation is working:</p>
<ul>
<li><p>Fewer repetitive questions in community channels.</p>
</li>
<li><p>Higher volunteer retention and satisfaction scores.</p>
</li>
<li><p>Faster integration of new members into community activities.</p>
</li>
<li><p>More consistent execution of events and programs.</p>
</li>
<li><p>Reduced administrative burden on community organizers.</p>
</li>
</ul>
<h2 id="heading-how-to-maintain-documentation-as-your-community-evolves">How to Maintain Documentation as Your Community Evolves</h2>
<p>Documentation requires ongoing attention to remain useful as your community grows and changes.</p>
<h3 id="heading-how-to-schedule-regular-review-cycles">How to Schedule Regular Review Cycles</h3>
<p>Establish predictable times for updating and improving your documentation:</p>
<ul>
<li><p>Monthly reviews of frequently-used resources like onboarding materials.</p>
</li>
<li><p>Quarterly comprehensive reviews following major events or program cycles.</p>
</li>
<li><p>Annual documentation audits to remove outdated information and improve organization.</p>
</li>
<li><p>Immediate updates when processes change or new information becomes available.</p>
</li>
</ul>
<h3 id="heading-how-to-create-systems-for-community-input">How to Create Systems for Community Input</h3>
<p>Make it easy for community members to suggest improvements and contribute updates. Simple contribution methods:</p>
<ul>
<li><p>Feedback forms or shared documents for quick suggestions.</p>
</li>
<li><p>Regular "documentation improvement" sessions during community meetings.</p>
</li>
<li><p>Recognition programs for members who contribute helpful updates.</p>
</li>
<li><p>Clear guidelines explaining how community members can suggest or make changes.</p>
</li>
</ul>
<h3 id="heading-how-to-build-documentation-updates-into-regular-workflows">How to Build Documentation Updates into Regular Workflows</h3>
<p>Instead of treating documentation as separate work, integrate updates into existing community management processes:</p>
<ul>
<li><p>Include documentation reviews in event planning checklists.</p>
</li>
<li><p>Assign specific documentation responsibilities to team members.</p>
</li>
<li><p>Make documentation accuracy part of program evaluation processes.</p>
</li>
<li><p>Train multiple people to update and maintain critical resources.</p>
</li>
</ul>
<h2 id="heading-how-to-create-a-culture-of-clear-communication">How to Create a Culture of Clear Communication</h2>
<p>The most effective community documentation happens when your entire team values clarity and considers member experience in every decision.</p>
<h3 id="heading-how-to-model-excellent-communication-practices">How to Model Excellent Communication Practices</h3>
<p>As a community leader, your communication style influences how everyone else approaches sharing information. Ways to model good documentation habits:</p>
<ul>
<li><p>Always include context when making announcements or giving instructions.</p>
</li>
<li><p>Follow up on frequently asked questions with documentation improvements.</p>
</li>
<li><p>Acknowledge and appreciate team members who create helpful resources.</p>
</li>
<li><p>Treat documentation work as valuable community contribution, not administrative overhead.</p>
</li>
</ul>
<h3 id="heading-how-to-integrate-clarity-into-decision-making">How to Integrate Clarity into Decision-Making</h3>
<p>Make "Will this be clear to community members?" a standard question in your planning processes. Consider documentation impact when:</p>
<ul>
<li><p>Launching new programs or changing existing procedures.</p>
</li>
<li><p>Planning events or community initiatives.</p>
</li>
<li><p>Onboarding new team members or volunteers.</p>
</li>
<li><p>Responding to community feedback and implementing improvements.</p>
</li>
</ul>
<h3 id="heading-how-to-recognize-clear-communication">How to Recognize Clear Communication</h3>
<p>When community members create helpful resources, explain things well, or improve existing documentation, make sure their contribution is acknowledged and valued. This recognition encourages others to consider community accessibility and take ownership of shared information resources.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Effective community documentation is not about perfect writing or exhaustive detail. It is about understanding what your community members need and creating clear paths for them to succeed.</p>
<p>You've learned how to organize information around member goals, write instructions that prevent confusion, and build systems that keep documentation relevant as your community grows. Most importantly, you've discovered how to promote a culture where clear communication is valued and community accessibility becomes everyone's responsibility.</p>
<p>Remember, this key principle: good community documentation is measured by member success and community health, not by volume or technical perfection. When new members can easily find ways to get involved, volunteers feel confident in their roles, and your community operates smoothly without requiring constant intervention, your documentation is fulfilling its purpose.</p>
<p>Start with one small improvement. Choose a process that generates frequent questions, apply these techniques, and observe the impact on your community's experience. Each improvement is a step toward building a truly sustainable, welcoming tech community where everyone can contribute effectively.</p>
<p>You can also connect with me on <a target="_blank" href="https://www.linkedin.com/in/oluwaseun-oladeji/">LinkedIn</a>, <a target="_blank" href="https://x.com/Oladejioluwas15">X (Twitter)</a> and <a target="_blank" href="https://medium.com/@oladejioluwaseun891">Medium</a>. If you made it to the end of this tutorial, thanks for reading!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Automate API Documentation Updates with GitHub Actions and OpenAPI Specifications ]]>
                </title>
                <description>
                    <![CDATA[ Maintaining up-to-date API documentation is often one of the biggest pain points for developers and teams. Too often, the API spec changes but the docs lag behind, leaving developers with outdated or inconsistent information. This frustrates consumer... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-automate-api-documentation-updates-with-github-actions-and-openapi-specifications/</link>
                <guid isPermaLink="false">68c0398aeff4d53c8494c5ab</guid>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ github-actions ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OpenApi ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ EZINNE ANNE EMILIA ]]>
                </dc:creator>
                <pubDate>Tue, 09 Sep 2025 14:28:26 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757428080226/175085d0-cfea-41a0-aa52-a50ad8212980.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Maintaining up-to-date API documentation is often one of the biggest pain points for developers and teams. Too often, the API spec changes but the docs lag behind, leaving developers with outdated or inconsistent information. This frustrates consumers of your API and increases support overhead.</p>
<p>This is where automation comes in. By combining OpenAPI specifications with GitHub Actions, you can ensure your documentation is always in sync with your API changes.</p>
<ul>
<li><p><strong>OpenAPI</strong> acts as the single reference point for your API design, keeping your docs consistent, accurate, and aligned with your API.</p>
</li>
<li><p><strong>GitHub Actions</strong> automates the workflow, validating your spec, building docs, and publishing to GitHub Pages in seconds.</p>
</li>
</ul>
<p>This tutorial walks you through a working example of how to use GitHub Actions to auto-update your docs.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-repository">How to set up your repository</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-the-openapi-specification">How to Create the OpenAPI Specification</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-test-the-api-spec-locally">How to Test the API Spec Locally</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-install-tools">Install tools</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-create-a-landing-page">Create a landing page</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-validate-your-spec">Validate Your Spec</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-preview-in-the-browser">Preview in the Browser</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-push-local-changes-to-github">How to Push Local Changes to GitHub</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-your-github-actions-workflow">How to Set Up Your GitHub Actions Workflow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-github-pages">How to Set Up GitHub Pages</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-github-pages">What is GitHub Pages?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-up-github-pages">Setting Up GitHub Pages</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-handle-multiple-versions">How to Handle Multiple Versions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-about-the-versions">About the Versions</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-version-1-v1">Version 1 (v1)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-version-2-v2">Version 2 (v2)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-version-3-v3">Version 3 (v3)</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-versions-locally">How to Set Up the Versions Locally</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-validate-the-api-specs">How to Validate the API Specs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-update-the-github-actions-workflow">How to Update the GitHub Actions Workflow</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p><a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">Node.js and npm installed.</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/gitting-things-done-book/">A GitHub account with basic Git knowledge.</a></p>
</li>
<li><p><a target="_blank" href="https://code.visualstudio.com/download">Visual Studio Code Editor</a>.</p>
</li>
<li><p><a target="_blank" href="https://idratherbewriting.com/learnapidoc/">Basic knowledge of documentation and OpenAPI</a>.</p>
</li>
</ul>
<h2 id="heading-how-to-set-up-your-repository">How to Set Up Your Repository</h2>
<p>If you don’t already have one, create a GitHub repository. For this tutorial, I’ll use <code>api-docs</code> as the repo name.</p>
<p>Then open VSCode and create a folder with the same name.</p>
<h2 id="heading-how-to-create-the-openapi-specification">How to Create the OpenAPI Specification</h2>
<p>Inside the folder you just created, create a folder called <code>spec</code> and add a file named <code>greetings.yaml</code> with the following content:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">openapi:</span> <span class="hljs-number">3.0</span><span class="hljs-number">.3</span>
<span class="hljs-attr">info:</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">Greetings</span> <span class="hljs-string">API</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
  <span class="hljs-attr">description:</span> <span class="hljs-string">This</span> <span class="hljs-string">is</span> <span class="hljs-string">a</span> <span class="hljs-string">greetings</span> <span class="hljs-string">API</span> <span class="hljs-string">demonstrating</span> <span class="hljs-string">a</span> <span class="hljs-string">simple</span> <span class="hljs-string">greeting</span> <span class="hljs-string">endpoint</span> <span class="hljs-string">with</span> <span class="hljs-string">query</span> <span class="hljs-string">parameters</span> <span class="hljs-string">and</span> <span class="hljs-string">multilingual</span> <span class="hljs-string">support.</span>
  <span class="hljs-attr">license:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">MIT</span>
    <span class="hljs-attr">url:</span> <span class="hljs-string">https://opensource.org/licenses/MIT</span>
<span class="hljs-attr">servers:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://api.yourdomain.com/v1</span>
    <span class="hljs-attr">description:</span> <span class="hljs-string">Production</span> <span class="hljs-string">server(v1)</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">url:</span> <span class="hljs-string">https://staging.yourdomain.com/v1</span>
    <span class="hljs-attr">description:</span> <span class="hljs-string">Staging</span> <span class="hljs-string">server(v1)</span>
<span class="hljs-attr">security:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">api_key:</span> []
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/hello:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Returns</span> <span class="hljs-string">a</span> <span class="hljs-string">greeting</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">getGreeting</span>
      <span class="hljs-attr">parameters:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">name</span>
          <span class="hljs-attr">in:</span> <span class="hljs-string">query</span>
          <span class="hljs-attr">required:</span> <span class="hljs-literal">false</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Name</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">person</span> <span class="hljs-string">to</span> <span class="hljs-string">greet</span>
          <span class="hljs-attr">schema:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
            <span class="hljs-attr">example:</span> <span class="hljs-string">Ezinne</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">lang</span>
          <span class="hljs-attr">in:</span> <span class="hljs-string">query</span>
          <span class="hljs-attr">required:</span> <span class="hljs-literal">false</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Language</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">greeting</span> <span class="hljs-string">(default</span> <span class="hljs-string">is</span> <span class="hljs-string">English)</span>
          <span class="hljs-attr">schema:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
            <span class="hljs-attr">enum:</span> [<span class="hljs-string">en</span>, <span class="hljs-string">fr</span>, <span class="hljs-string">es</span>, <span class="hljs-string">ig</span>]
            <span class="hljs-attr">example:</span> <span class="hljs-string">en</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Successful</span> <span class="hljs-string">response</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
                <span class="hljs-attr">properties:</span>
                  <span class="hljs-attr">message:</span>
                    <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">examples:</span>
                <span class="hljs-attr">english:</span>
                  <span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Hello, Ezinne!"</span> }
                <span class="hljs-attr">french:</span>
                  <span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Bonjour, Ezinne!"</span> }
                <span class="hljs-attr">spanish:</span>
                  <span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"¡Hola, Ezinne!"</span> }
                <span class="hljs-attr">igbo:</span>
                  <span class="hljs-attr">value:</span> { <span class="hljs-attr">message:</span> <span class="hljs-string">"Ndeewo, Ezinne!"</span> }
<span class="hljs-attr">components:</span>
  <span class="hljs-attr">securitySchemes:</span>
    <span class="hljs-attr">api_key:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">apiKey</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">Authorization</span>
      <span class="hljs-attr">in:</span> <span class="hljs-string">header</span>
</code></pre>
<p>This is a simple spec with multilingual greetings. As your API grows (say more languages or versions), keeping docs in sync manually might get tedious. That’s why automation helps.</p>
<h2 id="heading-how-to-test-the-api-spec-locally">How to Test the API Spec Locally</h2>
<h3 id="heading-install-tools">Install tools:</h3>
<p>Before setting GitHub Actions, you can test the API Spec locally on your machine by setting up <a target="_blank" href="https://github.com/Redocly">Redocly</a> (used to be called Redoc) and testing it in an HTML environment.</p>
<p>Redocly is a lightweight, customizable tool to render OpenAPI specs as an interactive HTML documentation. It’s ideal for static site deployment which makes it ideal for this scenario.</p>
<ul>
<li><p>Install Redoc globally with <code>npm install -g @redocly/cli</code></p>
</li>
<li><p>Install http-server globally with <code>npm install -g http-server</code></p>
</li>
</ul>
<p>The http-server is a local server you can use to test the doc on your machine before you push to GitHub and deploy to GitHub Pages.</p>
<h3 id="heading-create-a-landing-page">Create a landing page:</h3>
<p>In your project, make a <code>docs</code> folder and add <code>index.html</code>:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>API Documentation<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">redoc</span> <span class="hljs-attr">spec-url</span>=<span class="hljs-string">"../spec/greetings.yaml"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">redoc</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-validate-your-spec">Validate Your Spec:</h3>
<p><code>redocly lint spec/greetings.yaml</code></p>
<p>You should see this if there are no errors or warnings:</p>
<pre><code class="lang-powershell">Woohoo! Your API description is valid. 🎉
</code></pre>
<p><strong>Note:</strong> Validating your API Spec before testing is important as it’ll flag any possible errors. This is because Redocly will fail to run the preview if there are any errors in your spec. </p>
<h3 id="heading-preview-in-the-browser">Preview in the browser:</h3>
<p>Run <code>http-server</code>, and you should see this in the terminal:</p>
<pre><code class="lang-powershell">Starting up http<span class="hljs-literal">-server</span>, serving ./
Available on:
  http://<span class="hljs-number">127.0</span>.<span class="hljs-number">0.1</span>:<span class="hljs-number">8080</span>
  http://<span class="hljs-number">192.168</span>.x.x:<span class="hljs-number">8080</span>
Hit CTRL<span class="hljs-literal">-C</span> to stop the server
</code></pre>
<p>Open <a target="_blank" href="http://localhost:8080/docs/index.html"><code>http://127.0.0.1:8080/</code></a> and navigate to <code>/docs</code> to see your docs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756983802999/944b8603-7b2e-477a-8156-fdaa60f7e0af.png" alt="A preview of the API Specification in a Html page" class="image--center mx-auto" width="1894" height="865" loading="lazy"></p>
<h2 id="heading-how-to-push-local-changes-to-github">How to Push Local Changes to GitHub</h2>
<p>After making local changes, you need to set up the API documentation so it can update automatically whenever you make changes.</p>
<p>Run these commands if you are pushing to the repository for the first time:</p>
<pre><code class="lang-powershell">git init
git add .
git commit <span class="hljs-literal">-m</span> <span class="hljs-string">"first commit"</span>
git branch <span class="hljs-literal">-M</span> main
git remote add origin &lt;your<span class="hljs-literal">-repo</span><span class="hljs-literal">-url</span>&gt;
git push <span class="hljs-literal">-u</span> origin main
</code></pre>
<h2 id="heading-how-to-set-up-your-github-actions-workflow">How to Set Up Your GitHub Actions Workflow</h2>
<p>You can set up your GitHub workflow by creating a few folders.</p>
<p>First, create <code>.github/workflows/</code> in the <code>api-docs</code> folder. Then, inside the <code>workflows</code> folder, create a <code>docs.yml</code>. This is the workflow file that will serve as a trigger to run validation, generate the HTML with Redocly, and deploy to GitHub Pages at the same time.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">API</span> <span class="hljs-string">Documentation</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
    <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'spec/greetings.yaml'</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-spec:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">permissions:</span>
      <span class="hljs-attr">contents:</span> <span class="hljs-string">write</span> <span class="hljs-comment"># needed for gh-pages deployment</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># 1. Checkout repository</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-comment"># 2. Set up Node.js</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Node.js</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">'20'</span>

      <span class="hljs-comment"># 3. Install Redocly CLI</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Redocly</span> <span class="hljs-string">CLI</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">@redocly/cli</span>

      <span class="hljs-comment"># 4. Validate OpenAPI spec</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Validate</span> <span class="hljs-string">OpenAPI</span> <span class="hljs-string">Spec</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">redocly</span> <span class="hljs-string">lint</span> <span class="hljs-string">spec/greetings.yaml</span>

      <span class="hljs-comment"># 5. Build output directory</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">build</span> <span class="hljs-string">directory</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public</span>

      <span class="hljs-comment"># 6. Copy spec</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">spec</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/spec</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">cp</span> <span class="hljs-string">spec/greetings.yaml</span> <span class="hljs-string">public/spec/</span>

      <span class="hljs-comment"># 7. Copy landing page</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">landing</span> <span class="hljs-string">page</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">cp</span> <span class="hljs-string">docs/index.html</span> <span class="hljs-string">public/index.html</span>

      <span class="hljs-comment"># 8. Deploy to GitHub Pages</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">peaceiris/actions-gh-pages@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">github_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">publish_dir:</span> <span class="hljs-string">./public</span>
</code></pre>
<p>Here’s what’s going on in this code:</p>
<ul>
<li><p>Runs when changes are pushed to <code>main</code> that affect <code>spec/greetings.yaml</code>.</p>
</li>
<li><p>Checks out the repo code.</p>
</li>
<li><p>Sets up Node.js and installs Redocly.</p>
</li>
<li><p>Validates your OpenAPI spec (so broken specs won’t deploy).</p>
</li>
<li><p>Copies the spec and index page into a <code>public/</code> folder.</p>
</li>
<li><p>Deploys <code>public/</code> to the <code>gh-pages</code> branch with GitHub Pages.</p>
</li>
</ul>
<p>Since we’re done with local testing, update the file path in the <code>index.html</code>:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>API Documentation<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">redoc</span> <span class="hljs-attr">spec-url</span>=<span class="hljs-string">"./spec/greetings.yaml"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">redoc</span>&gt;</span> <span class="hljs-comment">&lt;!--update the filepath to match your gh config--&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This is so the <code>public</code> directory in the workflow will be able to access it correctly.</p>
<p>This workflow will only run when it detects changes in the API Spec (<code>greetings.yml</code>). To see the workflow in action, make a minor edit in the <code>greetings.yaml</code>.</p>
<p>Push the changes to your GitHub repository:</p>
<pre><code class="lang-powershell">git add .
git commit <span class="hljs-literal">-m</span> <span class="hljs-string">'add changes'</span>
git push
</code></pre>
<h2 id="heading-how-to-set-up-github-pages">How to Set Up GitHub Pages</h2>
<h3 id="heading-what-is-github-pages">What is GitHub Pages?</h3>
<p><a target="_blank" href="https://docs.github.com/en/pages/getting-started-with-github-pages/what-is-github-pages">GitHub Pages</a> is a hosting platform owned by GitHub where you can host websites directly from your GitHub account. This means you can publish static sites on the internet using a GitHub domain and anyone with the website link can access it.</p>
<p>There are other hosting platforms you can use to deploy static websites such as <a target="_blank" href="https://www.netlify.com/">Netlify</a> and <a target="_blank" href="https://vercel.com/">Vercel</a>. But using GitHub Pages for this documentation is easier to set up as it’s on the same platform.</p>
<h3 id="heading-setting-up-github-pages">Setting up GitHub Pages</h3>
<p>Set up GitHub Pages by clicking on the Settings tab in your repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756985360548/fa3518a7-0b44-4c7b-ae7f-d0e0b17a84c6.png" alt="A preview of the settings tab in the `api-docs` repository" class="image--center mx-auto" width="1909" height="865" loading="lazy"></p>
<p>Under Source, choose:</p>
<ul>
<li><p>Deploy from branch: <code>gh-pages</code></p>
</li>
<li><p>Folder: <code>/ (root)</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756985446692/a4774bcc-1a42-49f8-a9fd-8ca9339808ef.png" alt="A step-by-step preview of the gh-pages and root setup" class="image--center mx-auto" width="1669" height="525" loading="lazy"></p>
<p>Then save and wait for the workflow to finish.</p>
<p>Your docs will be live at: <code>https://&lt;username&gt;.github.io/api-docs</code>.</p>
<h2 id="heading-how-to-handle-multiple-versions">How to Handle Multiple Versions</h2>
<p>What if you had multiple API versions to update? Let’s assume the simple greetings API in this tutorial had more features added to it across different versions. In this case, you can manage the APIs for the different versions in a single page and also build and deploy it automatically. </p>
<h3 id="heading-about-the-versions">About the Versions</h3>
<h4 id="heading-version-1-v1">Version 1 (v1)</h4>
<p>This is the starting point which is <code>greetings.yaml</code>. The API only has a single <code>/hello</code> endpoint that returns a greeting in four languages (English, French, Spanish, or Igbo).</p>
<h4 id="heading-version-2-v2">Version 2 (v2)</h4>
<p>In version 2, the API adds create and read features. You can:</p>
<ul>
<li><p>Use <code>POST /hello</code> to create and save a greeting.</p>
</li>
<li><p>Retrieve greetings by their unique ID with <code>GET /hello/{id}</code>.</p>
</li>
</ul>
<h4 id="heading-version-3-v3">Version 3 (v3)</h4>
<p>Version 3 builds on top of v2 by adding an update functionality. Along with creating and retrieving greetings, you can now update an existing greeting using <code>PUT /hello/{id}</code>.</p>
<h3 id="heading-how-to-set-up-the-versions-locally">How to Set Up the Versions Locally</h3>
<p>First, create a <code>v1</code> folder and move the <code>greetings.yaml</code> file to it. Since we are going to be using versions, you can delete the existing <code>spec</code> folder.</p>
<p>Then, create a <code>v2</code> folder and create a <code>greetings-v2.yaml</code> file. <a target="_blank" href="https://ezinneanne.github.io/api-doc/v2/greetings-v2.yaml">Get the greetings API for version 2 here</a>.</p>
<p>Next, create a <code>v3</code> folder and add <code>greetings-v3.yaml</code> file. <a target="_blank" href="https://ezinneanne.github.io/api-doc/v3/greetings-v3.yaml">Get the greetings API for version 3 here</a>.</p>
<p>To follow the same pattern with others, rename the version 1 file to <code>greetings-v1.yaml</code>. Then update your <code>index.html</code> to accommodate the other two versions.</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>API Documentation<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"utf-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
      <span class="hljs-selector-tag">body</span> {
        <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
        <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
      }
      <span class="hljs-selector-tag">header</span> {
        <span class="hljs-attribute">background</span>: <span class="hljs-number">#2c3e50</span>;
        <span class="hljs-attribute">color</span>: white;
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">1rem</span>;
        <span class="hljs-attribute">display</span>: flex;
        <span class="hljs-attribute">justify-content</span>: space-between;
        <span class="hljs-attribute">align-items</span>: center;
      }
      <span class="hljs-selector-tag">select</span> {
        <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.4rem</span>;
        <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1rem</span>;
      }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>API Documentation<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"version"</span>&gt;</span>Version: <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"version"</span> <span class="hljs-attr">onchange</span>=<span class="hljs-string">"loadSpec()"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v1/greetings-v1.yaml"</span>&gt;</span>v1<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v2/greetings-v2.yaml"</span>&gt;</span>v2<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"./v3/greetings-v3.yaml"</span>&gt;</span>v3<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- ReDoc container --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"redoc-container"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- ReDoc script --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
      <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">loadSpec</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">const</span> version = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"version"</span>).value;
        Redoc.init(version, {}, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"redoc-container"</span>));
      }
      <span class="hljs-comment">// Load default (v1) on first load</span>
      <span class="hljs-built_in">window</span>.onload = loadSpec;
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="heading-how-to-validate-the-api-specs">How to Validate the API Specs</h3>
<p>Earlier in this article, I mentioned testing your specification locally. Now that you have two more versions of the greetings API, run the test to highlight and fix any existing errors.</p>
<ul>
<li><p>For the version V2: <code>redocly lint v2/greetings-v2.yaml</code></p>
</li>
<li><p>For the version V3: <code>redocly lint v3/greetings-v3.yaml</code></p>
</li>
</ul>
<h3 id="heading-how-to-update-the-github-actions-workflow">How to Update the GitHub Actions Workflow</h3>
<p>Now that you have three API Spec versions, you need to update your workflow so it will monitor the three spec files and the HTML document for changes, and then push and deploy them to GitHub Pages as well.</p>
<p>Add this to your <code>.github/workflows/docs.yml</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Name of the workflow</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">API</span> <span class="hljs-string">Documentation</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]
    <span class="hljs-attr">paths:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'docs/index.html'</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'v1/greetings-v1.yaml'</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'v2/greetings-v2.yaml'</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'v3/greetings-v3.yaml'</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">permissions:</span>
      <span class="hljs-attr">contents:</span> <span class="hljs-string">write</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># 1. Checkout the repository</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">repository</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v4</span>

      <span class="hljs-comment"># 2. Create build directory</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Create</span> <span class="hljs-string">build</span> <span class="hljs-string">directory</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public</span>

      <span class="hljs-comment"># 3. Copy YAML specs into public folder</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v1</span> <span class="hljs-string">spec</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v1</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">cp</span> <span class="hljs-string">v1/greetings-v1.yaml</span> <span class="hljs-string">public/v1/</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v2</span> <span class="hljs-string">spec</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v2</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">cp</span> <span class="hljs-string">v2/greetings-v2.yaml</span> <span class="hljs-string">public/v2/</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">v3</span> <span class="hljs-string">spec</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">-p</span> <span class="hljs-string">public/v3</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">cp</span> <span class="hljs-string">v3/greetings-v3.yaml</span> <span class="hljs-string">public/v3/</span>

      <span class="hljs-comment"># 4. Copy landing page into public</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Copy</span> <span class="hljs-string">landing</span> <span class="hljs-string">page</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">cp</span> <span class="hljs-string">docs/index.html</span> <span class="hljs-string">public/index.html</span>

      <span class="hljs-comment"># 5. Deploy to GitHub Pages</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">peaceiris/actions-gh-pages@v4</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">github_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">publish_dir:</span> <span class="hljs-string">./public</span>
</code></pre>
<p>And finally, push the changes and reload the site. This should showcase the updated documentation.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756986868235/9de187f1-12c4-46ca-a73b-daafa353ed1f.png" alt="A preview of the API documentation in a hosted GitHub Pages environment" class="image--center mx-auto" width="1894" height="868" loading="lazy"></p>
<h2 id="heading-summary">Summary</h2>
<p>In this tutorial, you have learned how to auto-update your API docs. We started with a single OpenAPI spec and a basic HTML page rendered by Redocly, and tested it locally. We then set up GitHub Actions to automatically validate the spec, copy the files, and deploy the docs to GitHub Pages. Finally, we extended the setup to handle multiple API versions in one place.</p>
<p>With this workflow, your documentation stays accurate, up-to-date, and hassle-free so every change you make to your API spec goes live when you push the changes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Documentation That Increases Sign-ups ]]>
                </title>
                <description>
                    <![CDATA[ Writing documentation looks easy, but it is one of the most critical parts of your customer support and growth strategy. Too often, teams treat it as an afterthought – just add a few code snippets and move on. But if you’re serious about product adop... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-documentation-that-increases-sign-ups/</link>
                <guid isPermaLink="false">68542e3585d4833f32068976</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Technical writing  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tooba Jamal ]]>
                </dc:creator>
                <pubDate>Thu, 19 Jun 2025 15:35:17 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750347297168/f873d57d-22e5-4cbb-bda9-ca24861db09d.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Writing documentation looks easy, but it is one of the most critical parts of your customer support and growth strategy. Too often, teams treat it as an afterthought – just add a few code snippets and move on.</p>
<p>But if you’re serious about product adoption, your docs need to do more than exist. They need to guide, support, and convert. In this tutorial, we’ll break down how to write documentation that actually helps users and gets them to stick around.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-whats-the-problem-with-most-documentation">What’s the Problem with Most Documentation?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-write-documentation-from-the-users-perspective">How to Write Documentation from the User’s Perspective</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-start-by-understanding-your-users">Start by Understanding Your Users</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-structure-around-the-four-documentation-types">Structure Around the Four Documentation Types</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-make-it-easy-to-reach-out">Make it Easy to Reach Out</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-keep-your-tech-team-in-the-loop">Keep Your Tech Team in the Loop</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-reuse-what-youve-already-written">Reuse What You’ve Already Written</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-get-ai-help-the-smart-way">Get AI Help (The Smart Way)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-get-feedback-early">Get Feedback Early</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-does-documentation-increase-sign-ups">How Does Documentation Increase Sign-ups?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-making-complex-documentation-accessible">Making Complex Documentation Accessible</a></p>
</li>
</ul>
<h2 id="heading-whats-the-problem-with-most-documentation">What’s the Problem with Most Documentation?</h2>
<p>The most common problem with documentation is that its authors believe their audience knows everything. This leads to the loss of many potential leads – causing people to abandon your platform before even fully understanding it.</p>
<p>Here’s why:</p>
<ul>
<li><p>It’s often dry and code-heavy, with snippets and vague bullet points.</p>
</li>
<li><p>It dumps information and expects the readers to figure it out.</p>
</li>
<li><p>It’s written from the developer’s point of view, not the user’s.</p>
</li>
<li><p>It rarely shows how the product fits into the user’s specific use case or workflow.</p>
</li>
<li><p>It combines different content types into a chaotic mess that’s difficult to follow or navigate.</p>
</li>
</ul>
<h2 id="heading-how-to-write-documentation-from-the-users-perspective">How to Write Documentation from the User’s Perspective</h2>
<p>Most documentation is written from a developer’s perspective: technical, feature-first, and dry. But at the end of the day, developers are also humans with problems like others, and when browsing your documentation, they are asking:</p>
<ul>
<li><p>“Can this solve my problem?”</p>
</li>
<li><p>“How do I get it working for my use case?”</p>
</li>
<li><p>“What happens if I get stuck?”</p>
</li>
</ul>
<p>Here’s how you can make people stay and come back to your documentation.</p>
<h3 id="heading-start-by-understanding-your-users">Start by Understanding Your Users</h3>
<p>Before writing a single line of documentation, pause and ask: What do our users actually care about? And it's more than just “connect an API to their client’s app”. It's the intangible benefits they’re seeking, such as two hours saved due to your tool while connecting the API or collecting payments from different clients with a single workflow.</p>
<p>This means that you need to listen before you write.</p>
<p>Dig into conversations happening around your product, not just within it. What questions do users consistently ask during sales calls? What pain points come up in Reddit threads or support tickets? What complaints are circulating on social media that haven’t been addressed yet?</p>
<p>Pay close attention to the words they use while referring to your product.</p>
<p>When you use their words, not yours, your documentation starts to sound like a helpful guide, not a technical manual. That shift alone can be the difference between “let me try this tool” and “I’ll figure it out later.”</p>
<p>Supabase is a good example of user-friendly docs. It begins by categorizing content by product, module, and client library. Each category includes comprehensive documentation with real-world examples, practical use cases, tutorials, and built-in feedback support.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750260785373/46bdc0af-3de8-42c3-bd36-02390db5df2d.png" alt="Screenshot from Supabase's docs" class="image--center mx-auto" width="1897" height="902" loading="lazy"></p>
<h3 id="heading-structure-around-the-four-documentation-types">Structure Around the Four Documentation Types</h3>
<p>Now that you know your customer, your job is to guide them to the correct answer fast. That’s hard to do if everything’s thrown together in one long page. Structure is what turns chaos into clarity.</p>
<p>The best documentation systems categorize information into four types, a <a target="_blank" href="https://docs.divio.com/documentation-system/">framework</a> originally proposed by Divio. Not just different sections, but completely different purposes. Each one meets your user at a different stage of their journey.</p>
<p>Let’s break them down:</p>
<h4 id="heading-1-quickstart">1. Quickstart</h4>
<p>This is the user’s first real experience with your product, and it’s where they decide whether to continue using it. So your job here isn’t to explain everything. It’s to walk them through one thing that works. Slowly. Clearly. And in their language.</p>
<p>Use examples. Don’t assume prior knowledge. Avoid jargon unless you’ve already explained it. The goal is to create that first “Oh, I get it now” moment. Because once they’ve had it, they’ll stick around for more.</p>
<p>For example, the <a target="_blank" href="https://react.dev/learn">React documentation</a> gives beginners a simple walkthrough, from creating a component to passing data between them. It avoids jargon, focuses on one working example, and explains each step clearly. This helps users quickly grasp how React works, creating that first “Oh, I get it now” moment.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750243332841/7a1f98f2-24b1-400c-aadd-0534419b0379.png" alt="Screenshot of the React docs" class="image--center mx-auto" width="1895" height="853" loading="lazy"></p>
<h4 id="heading-2-how-to-guides">2. How-to Guides</h4>
<p>These are for users who already know the basics and just want to solve a problem. “How do I connect this to Slack?” “How do I export this as a CSV?” They’re not here to learn concepts. They just want to follow instructions and get something done.</p>
<p>Start by telling them exactly what the guide will help them do. List prerequisites up front if needed. Then walk them through the steps.</p>
<p>For example, the <a target="_blank" href="https://www.tensorflow.org/tutorials/images/cnn">TensorFlow documentation</a> includes a step-by-step guide on how to build a Convolutional Neural Network (CNN) to classify images. It’s task-focused and practical, so anyone trying to implement image classification with TensorFlow knows exactly where to go and what steps to follow.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750243604478/992a12b3-12fb-4c17-a5ec-713e67a49bae.png" alt="Screenshot from the TensorFlow docs" class="image--center mx-auto" width="1896" height="907" loading="lazy"></p>
<h4 id="heading-3-technical-reference">3. Technical Reference</h4>
<p>This is where the raw details live. Your endpoints, CLI commands, Parameter lists, what happens when something fails, and so on. Think of it like a glossary of your tool.</p>
<p>People scan this portion of your documentation, so make it easy to scan. Organize it so someone can jump to what they need. Use consistent formatting and avoid explanations here, but add links to the explanations sections.</p>
<p>For example, the <a target="_blank" href="https://kubernetes.io/docs/home/">Kubernetes documentation</a> includes a comprehensive API reference that lists all available resources, their fields, default values, and behaviors. It’s organized into categories like common parameters and workload resources, making it easy to navigate. Each section focuses on definitions and parameters, with links to related conceptual docs for deeper context.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750244073207/d6c7fddb-8bac-4c25-9fad-b83f2bf8fc72.png" alt="Screenshot from the Kubernetes docs" class="image--center mx-auto" width="1896" height="902" loading="lazy"></p>
<h4 id="heading-4-explanations">4. Explanations</h4>
<p>This is where you step back and explain the thinking behind your system. Why does your product rely on webhooks? Why did you structure your SDK a certain way? When should someone use one method over another?</p>
<p>This part differentiates your tool from the crowd and builds trust. Yet, many documentations miss this. Don’t forget to add a separate section on common errors beyond 404s here. The errors that people encounter when using your tool provide a straightforward solution to those errors.</p>
<p>For example, <a target="_blank" href="https://docs.divio.com/">Divio</a> has an explanation section in its documentation that covers each relevant concept in detail. It starts by explaining the concept itself, then shows how it works within Divio and what practical applications it has. This helps users understand the reasoning behind the system and how to use it effectively.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750244241171/f37e28f5-7c8b-4a2d-bf9b-bd99edf6fa9e.png" alt="Screenshot from the Divio docs" class="image--center mx-auto" width="1893" height="901" loading="lazy"></p>
<h3 id="heading-make-it-easy-to-reach-out">Make it Easy to Reach Out</h3>
<p>Even with perfect docs, users will get stuck. And the worst thing you can do now is make them hunt for help.</p>
<p>Make it ridiculously easy to reach out.</p>
<p>Add a simple “Was this helpful?” prompt at the end of each page. If the answer is no, give them a quick way to say why.</p>
<p>Drop in a link to report bugs, outdated steps, or confusing content. You’ll get real-time feedback from real users.</p>
<p>Invite them to contact support or drop a question in your community Slack or Discord. It’s not just about solving issues. It’s about showing them you’re listening.</p>
<h3 id="heading-keep-your-tech-team-in-the-loop">Keep Your Tech Team in the Loop</h3>
<p>You don’t need to know how every line of code works. But you <em>do</em> need a clear path to someone who does.</p>
<p>Set up a shared document, Notion page, or Slack thread where your development team can casually share technical decisions, temporary errors, important workarounds, and other relevant information. </p>
<p>Also, don’t be afraid to ask your devs directly. A 3-minute voice note or quick message like “Does this sound right to you?” can prevent a dozen user errors later..</p>
<h3 id="heading-reuse-what-youve-already-written">Reuse What You’ve Already Written</h3>
<p>Chances are, you've already explained 80% of what needs to go in your docs you just didn’t call it “documentation” at the time.</p>
<p>Start by digging through what’s already there:</p>
<ul>
<li><p>Sales or support Slack threads where you broke things down clearly</p>
</li>
<li><p>Onboarding emails that walk users through the first steps</p>
</li>
<li><p>Internal guides your team relies on</p>
</li>
<li><p>Blog posts where you’ve explained product decisions</p>
</li>
<li><p>FAQs your support team sends on repeat</p>
</li>
</ul>
<p>Copy-paste, trim, reframe, and you’ve got a doc draft in minutes.</p>
<h3 id="heading-get-ai-help-the-smart-way">Get AI Help (The Smart Way)</h3>
<p>AI tools can cut your documentation time in half, but only if you treat them like a collaborator. One powerful way to use them is by turning raw code into structured docs. </p>
<p>Just drop in a code snippet or feature file and prompt something like: “Write a reference doc for this API endpoint. Include usage, parameters, response structure, and a working example.” </p>
<p>Then take it a step further: “Now rewrite this for a non-technical product manager who’s using the tool for the first time.” This way, you get both the technical version and a plain-English explanation without switching tabs ten times.</p>
<p>I used AI to generate the documentation for the <code>user.updated</code> webhook event, and here’s what it came up with. While the generated doc is functional, I’d like to improve it further.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1750261767771/e9db912c-5a3c-47e9-82cb-6661b4506e92.png" alt="e9db912c-5a3c-47e9-82cb-6661b4506e92" class="image--center mx-auto" width="995" height="805" loading="lazy"></p>
<p>Here are my initial thoughts:</p>
<ul>
<li><p>Avoid starting with generic phrases like “This document describes...”</p>
</li>
<li><p>Jump straight into what the <code>user.updated</code> event does</p>
</li>
<li><p>Remove unnecessary passive voice to improve clarity</p>
</li>
<li><p><strong>For example, instead of:</strong><br>  <em>"The</em> <code>user.updated</code> event is triggered when a user's profile is updated in the system."<br>  <strong>use:</strong><br>  <em>"Whenever a user profile is updated in your system, the</em> <code>user.updated</code> event is triggered."</p>
</li>
</ul>
<p>If the generated text sounds robotic, you can use an <a target="_blank" href="https://humanizerpro.ai/">AI humanizer</a> to make it more natural. Then, give it a final review to remove unnecessary content, add your voice, and ensure accuracy.</p>
<h3 id="heading-get-feedback-early">Get Feedback Early</h3>
<p>Don’t wait for the “final version” before asking for input. Documentation needs to be useful, and it’s better to get clarity early in the process. When you ask real humans for feedback on your documentation, you get a reality check before a customer spreads negative feedback about you.</p>
<p>Instead, test your docs in real-world conversations:</p>
<ul>
<li><p>Drop a how-to guide in your support team’s Slack and ask, “Would you send this to a user?”</p>
</li>
<li><p>Ask a teammate or friend to follow your tutorial. Watch where they pause or get confused.</p>
</li>
<li><p>Run it by sales or customer success, they know exactly where users get stuck in onboarding.</p>
</li>
</ul>
<p>And if you're just a small team of two people, ask each other. Then ask each other's friends. You don’t need a formal process, just honest reactions from real people.</p>
<h2 id="heading-how-does-documentation-increase-sign-ups">How Does Documentation Increase Sign-ups?</h2>
<p>When a developer first arrives at your documentation page, they give it a few minutes to decide whether your tool is worth using, especially if they’re still exploring options.</p>
<p>If they’re required to use your tool for any reason, they’ll likely spend a day or two trying to figure things out. If they can’t find the right information, the frustration builds and often escalates to upper management. That’s when you risk not just losing a user, but losing a team or even a larger client.</p>
<p>Good documentation prevents that.</p>
<p>It is well-structured, speaks to users at all levels, and is easy to navigate. It keeps users on your page longer and encourages them to test your tool instead of bouncing to a competitor. If you also offer feedback channels or live support, users are more likely to reach out when they get stuck, and that support interaction can make all the difference.</p>
<p>Good documentation:</p>
<ul>
<li><p>Reduces support dependency, so users spend more time building and less time troubleshooting</p>
</li>
<li><p>Lowers frustration, which signals maturity and product quality</p>
</li>
<li><p>Builds trust by showing that your team has thought through user needs</p>
</li>
<li><p>Helps users get something working quickly, which often turns into a sign-up</p>
</li>
</ul>
<h2 id="heading-making-complex-documentation-accessible">Making Complex Documentation Accessible</h2>
<p>Writing good docs requires careful planning, collaboration, and a solid understanding of your users. Whether your developers are writing it or you're working with a technical copywriter, excellent documentation is rarely a solo job. It requires input from the people who developed the product and those who support its users daily.</p>
<p>When done right, your docs don’t just explain things – they make your product more straightforward to use, build trust with potential customers, and drive sign-ups.</p>
<p>Liked what you read? I help SaaS companies clarify their messaging and build authority through content. You can connect with me on <a target="_blank" href="https://www.linkedin.com/in/tooba-jamal/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Documentation with docs.page – A Beginner's Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ One of the most tedious tasks for every startup, company, and open-source project is often building and managing documentation – especially for medium to large-scale documentation websites. docs.page is an open-source documentation tool that helps yo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-documentation-with-docspage/</link>
                <guid isPermaLink="false">681a558b9791d0e469b84519</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Beginner Developers ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rajdeep Singh ]]>
                </dc:creator>
                <pubDate>Tue, 06 May 2025 18:31:39 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746471569068/23f70d3e-a76e-4287-a6a9-579c23a4fcb2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>One of the most tedious tasks for every startup, company, and open-source project is often building and managing documentation – especially for medium to large-scale documentation websites.</p>
<p><a target="_blank" href="http://docs.page"><strong>docs.page</strong></a> is an open-source documentation tool that helps you create instant, fast, beautiful, and responsive documentation websites with minimal configuration. It is an open-source project developed by Invertase, a company known for creating developer tools and SDKs.</p>
<p>docs.page is designed to streamline the process of publishing documentation by sourcing content directly from public GitHub repositories.</p>
<h3 id="heading-key-features">Key Features:</h3>
<ul>
<li><p>Zero configuration: you create a 'docs.json' file and a 'docs' directory. Inside the docs directory, you can create files using the .mdx extension, and docs.page will generate your documentation site.</p>
</li>
<li><p>Customizable: docs.page allows you to add your logo, social links, theme, analytics, navigation, and more through a simple configuration file.</p>
</li>
<li><p>Live previews: enables viewing of documentation for any branch, pull request, or specific commit, facilitating real-time collaboration and review.</p>
</li>
<li><p>Hot reload: the Hot Reload feature provides real-time previews of documentation changes while editing Markdown (.mdx) files. This feature enhances the local development workflow, enabling instant updates without manual refreshes or rebuilds.</p>
</li>
<li><p>GitHub bot integration: provides a GitHub bot that automatically generates URLs for pull request documentation previews.</p>
</li>
<li><p>MDX support: you can write documentation in Markdown to utilize MDX, which enables you to use React components, such as tabs, Cards, Tweets, and Steps, directly within your Markdown file.</p>
</li>
<li><p>Search functionality: integrates with DocSearch to offer full-text search capabilities within your documentation.</p>
</li>
<li><p>Responsive resign: ensures that your documentation is accessible and visually appealing across a range of devices and screen sizes.</p>
</li>
<li><p>Dark/light mode: offers theme customization to switch between dark and light modes.</p>
</li>
<li><p>Code block highlighting: provides syntax highlighting and content copying features for code blocks.</p>
</li>
</ul>
<p>Check out the code <a target="_blank" href="https://github.com/officialrajdeepsingh/docs-page-demo">available in my GitHub repository</a>.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents:</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-does-docspage-work">How Does</a> <a target="_blank" href="http://docs.page">docs.page</a> <a class="post-section-overview" href="#heading-how-does-docspage-work">Work?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-enable-live-preview-in-docspage">How to Enable Live Preview in</a> <a target="_blank" href="http://docs.page">docs.page</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-configure-docspage">How to Configure</a> <a target="_blank" href="http://docs.page">docs.page</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-pre-built-components-in-docspage">How to Use Pre-built Components in</a> <a target="_blank" href="http://docs.page">docs.page</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-diagnose-errors-in-docspage">How to Diagnose Errors in</a> <a target="_blank" href="http://docs.page">docs.page</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-use-frontmatter">How to Use Frontmatter</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-add-assets-to-your-docs">How to Add Assets to Your Docs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-publish-your-documentation-website">How to Publish Your Documentation Website</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-can-you-live-preview-your-upcoming-changes-to-your-documentation-website">How can you live preview your upcoming changes to your documentation website?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-how-does-docspage-work">How Does docs.page Work?</h2>
<p>You can easily start creating your documentation page using the <a target="_blank" href="https://use.docs.page/cli">docs.page CLI</a>. It helps you set up a local documentation project by running the following command:</p>
<pre><code class="lang-bash">pnpm dlx @docs.page/cli init docs.page
</code></pre>
<p>The command output appears as follows:</p>
<pre><code class="lang-bash">pnpm dlx @docs.page/cli init docs.page
? Are you sure you want to setup and install docs.page <span class="hljs-keyword">in</span> /home/officialrajdeepsingh/medium/docs.page? yes
Files created:
 - docs.json: Configuration file <span class="hljs-keyword">for</span> your documentation site
 - docs/index.mdx: The home page of your documentation site
 - docs/next-steps.mdx: A page to <span class="hljs-built_in">help</span> you get started with docs.page

Initialization complete. To preview your documentation site, vist https://docs.page/preview <span class="hljs-keyword">in</span> your browser.
</code></pre>
<p>After creating your project with the docs.page CLI, your project structure should appear as follows:</p>
<pre><code class="lang-bash">.
├── docs
│   ├── index.mdx
│   └── next-steps.mdx
└── docs.json

2 directories, 3 files
</code></pre>
<p>The <code>docs</code> folder contains the Markdown file for your documentation, and the <code>docs.json</code> file includes the configuration for your website, such as the header, sidebar, logo, theme, and other settings.</p>
<h2 id="heading-how-to-enable-live-preview-in-docspage">How to Enable Live Preview in docs.page</h2>
<p>You can set up live preview of your local documentation in real-time in the browser – but it's a little different: you don't need to run any development commands on your laptop or machine.</p>
<p>To open the live preview of your local documentation, first visit <a target="_blank" href="https://docs.page">https://docs.page</a> and click the <strong>Local Preview</strong> button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745671253187/c2e6ce0b-aedb-4e7e-b680-68e590fc4018.png" alt="Live preview your local documentation in real-time directly in the browser." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Next, select the documentation project on your laptop or machine and click the "<strong>Select Directory</strong>" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745664832273/fc03e2d5-02c0-4bce-b40c-a2599ef72195.png" alt=" click on the &quot;Select Directory&quot; button and select directory" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>After clicking the "Select Directory" button, a new window will open depending on your operating system. Its UI may appear different. Then you need to select the project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745664861969/39a31043-22e8-4d6b-a883-19be0a59ca4d.png" alt="Select the Directory" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>After selecting the folder, you will see the following alert message in the browser (“Let site view files?”). To view the live preview of your documentation website, click the "View files" button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745664971450/8ec6f635-a2e4-401e-8fa8-cf49c4e06b9a.png" alt="Click on View files button" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now you can see a local live preview of the documentation website in the browser, and any changes you make locally will instantly reflect in the browser. By default, your documentation website should appear as follows:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745674174727/dd4f1820-ce04-4244-b395-b055bb8d236a.png" alt="Live preview your documentation website in the browser" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Next, you’ll learn about configuring the Logo, Theme, Header, Social Links, Sidebar, SEO, search, and more on your docs. You’ll also learn how to use the pre-built components, Front Matter, and assets on docs.page, and finally, how to deploy your documentation website.</p>
<h2 id="heading-how-to-configure-docspage">How to Configure docs.page</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745834873075/6c9dd17b-20e2-40dc-87a1-39cc27cf9a20.png" alt="Configure docs.page in the docs.json file." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The <code>docs.json</code> file is the primary file for configuring your documentation. Below is a <a target="_blank" href="https://use.docs.page/configuration">list of all available configuration options</a>, which you can use to modify the logos, theme, analytics, and more on your docs.</p>
<h3 id="heading-properties"><strong>Properties</strong></h3>
<ul>
<li><p>Basic properties</p>
</li>
<li><p>Logo</p>
</li>
<li><p>Theme</p>
</li>
<li><p>Header</p>
</li>
<li><p>Anchors</p>
</li>
<li><p>Social Links</p>
</li>
<li><p>SEO</p>
</li>
<li><p>Variables</p>
</li>
<li><p>Search</p>
</li>
<li><p>Scripts</p>
</li>
<li><p>Content</p>
</li>
<li><p>Tabs</p>
</li>
<li><p>Sidebar</p>
</li>
</ul>
<p>There’s so much you can configure using docs.page – but in this tutorial, we’ll focus on some of the most important options:</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-properties">Properties</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-basic-properties">Basic Properties</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-logo">Logo</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-theme">Theme</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-header">Header</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-social-links">Social Links</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-seo">SEO</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-search">Search</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-tabs">Tabs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-sidebar">Sidebar</a></p>
</li>
</ul>
<h3 id="heading-basic-properties">Basic Properties</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745915741849/802ba7e3-ae6b-4628-856f-0d78aa4e1bfc.png" alt="Basic properties such as name, description and favicon" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>docs.page includes basic common properties, such as name, description, and favicon, which is very important for SEO.</p>
<ul>
<li><p>name (string): The name of your project. It appears in the header and is used for things like SEO metadata.</p>
</li>
<li><p>description (string): A summary of your project. This is used in meta tags and social preview images.</p>
</li>
<li><p>favicon (string | Favicon object): Specifies the favicon shown in the browser tab. You can provide either a single string URL or use a Favicon object to define different icons for light and dark modes:</p>
<ul>
<li><p>light (string): URL for the favicon in light mode.</p>
</li>
<li><p>dark (string): URL for the favicon in dark mode.</p>
</li>
</ul>
</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Docs.page"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"Ship documentation, like you ship code"</span>,
  <span class="hljs-attr">"favicon"</span>: <span class="hljs-string">"https://static.invertase.io/assets/docs.page/docs-page-logo.png"</span>,
   # or
  <span class="hljs-attr">"favicon"</span>: {
    <span class="hljs-attr">"light"</span>: <span class="hljs-string">"https://cdn-icons-png.flaticon.com/24/9664/9664027.png"</span>,
    <span class="hljs-attr">"dark"</span>: <span class="hljs-string">"https://cdn-icons-png.flaticon.com/24/9643/9643115.png"</span>
  }
}
</code></pre>
<h3 id="heading-logo">Logo</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745750725706/1f3f2775-91d8-4365-88b4-1a43160d12c3.png" alt="Configure the logo for your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now it’s time to configure the logo for your documentation, which will appear in the header and be used for social preview images.</p>
<p>The minimum height of the logo must be 24px. You can provide URLS for both a light and a dark logo. If you only provide a light or dark logo, and it doesn't work, you may experience issues where your logo doesn't appear on the website when toggling the theme.</p>
<p>You can add the logo to the documentation in two ways:</p>
<ul>
<li>First way:</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"My Docs"</span>,
  <span class="hljs-attr">"logo"</span>: <span class="hljs-string">"https://cdn-icons-png.flaticon.com/24/2702/2702154.png"</span>,
}
</code></pre>
<ul>
<li>Second way:</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"My Docs"</span>,
  <span class="hljs-attr">"logo"</span>: {
    <span class="hljs-attr">"light"</span>: <span class="hljs-string">"https://cdn-icons-png.flaticon.com/24/2702/2702154.png"</span>,
    <span class="hljs-attr">"dark"</span>: <span class="hljs-string">"https://cdn-icons-png.flaticon.com/24/2702/2702172.png"</span>
  }
}
</code></pre>
<h3 id="heading-theme">Theme</h3>
<p>Configuring the theme in your documentation is easy. If you don’t provide a theme, the default theme will be used in your documentation.</p>
<p>docs.page includes a theme property in docs.json, which holds a Theme object as its value with the properties <code>defaultTheme</code>, <code>primary</code>, <code>primaryLight</code>, <code>backgroundLight</code>, and <code>backgroundDark</code>.</p>
<ul>
<li><p><code>defaultTheme</code>: You can select a theme, dark or light.</p>
</li>
<li><p><code>primary</code>: The primary colour is used for links, buttons, and other interactive elements.</p>
</li>
<li><p><code>primaryLight</code>: The <code>primaryLight</code> colour option is used in light mode. If your primary light option is not specified in the <code>docs.json</code> file, then the primary colour will be used.</p>
</li>
<li><p><code>primaryDark</code>: The <code>primaryDark</code> colour option is used in dark mode. If your <code>primaryDark</code> option is not specified in the <code>docs.json</code> file, then the primary color will be used.</p>
</li>
<li><p><code>backgroundLight</code>: The <code>backgroundLight</code> option is used to specify the background color of your documentation in light mode.</p>
</li>
<li><p><code>backgroundDark</code>: The <code>backgroundDark</code> option is used to specify the background color of your documentation in dark mode.</p>
</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"theme"</span>: {
    <span class="hljs-attr">"defaultTheme"</span>: <span class="hljs-string">"dark"</span>,
    <span class="hljs-attr">"primary"</span>: <span class="hljs-string">"#de40eb"</span>,
    <span class="hljs-attr">"primaryLight"</span>: <span class="hljs-string">"#BFA213"</span>,
    <span class="hljs-attr">"backgroundLight"</span>: <span class="hljs-string">"#e0cfff"</span>,
    <span class="hljs-attr">"backgroundDark"</span>: <span class="hljs-string">"#00101f"</span>
  },
}
</code></pre>
<h3 id="heading-header">Header</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745912602721/2430492a-8d58-4f4b-bc4c-e22f8cb7b52f.png" alt="configuration of the header in your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Configuring the header in your documentation includes the following properties: <code>showName</code>, <code>showThemeToggle</code>, <code>showGitHubCard</code>, and links.</p>
<ul>
<li><p><code>showName</code>: The <code>showName</code> option displays the documentation name next to the logo in the header and defaults it is true.</p>
</li>
<li><p><code>showThemeToggle</code>: The <code>showThemeToggle</code> option displays the theme toggle button in the header (and defaults to true).</p>
</li>
<li><p><code>showGitHubCard</code>: The <code>showGitHubCard</code> option displays the GitHub card in the header and defaults to true.</p>
</li>
<li><p>Links: The links option contains an array of Link objects to display a navigation in the header of your documentation.</p>
</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"header"</span>: {
    <span class="hljs-attr">"showName"</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">"showGitHubCard"</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">"links"</span>: [
      {
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"GitHub"</span>,
        <span class="hljs-attr">"href"</span>: <span class="hljs-string">"https://github.com/officialrajdeepsingh/docs-page-demo"</span>
      },
      {
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"X"</span>,
        <span class="hljs-attr">"href"</span>: <span class="hljs-string">"https://x.com/Official_R_deep"</span>
      },
      {
        <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Linkedin"</span>,
        <span class="hljs-attr">"href"</span>: <span class="hljs-string">"https://www.linkedin.com/in/officalrajdeepsingh"</span>
      }
    ]
  }
}
</code></pre>
<h3 id="heading-social-links">Social Links</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745910990442/f48a4b34-d20f-4155-b19a-d8af8a202801.png" alt="configuration of the social links in your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>The social option contains an object of key-value pairs where the key represents the social platform and the value corresponds to the username or ID. Here’s how you can add them:</p>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  <span class="hljs-attr">"social"</span>: {
    <span class="hljs-attr">"github"</span>: <span class="hljs-string">"officialrajdeepsingh/docs-page-demo"</span>,
    <span class="hljs-attr">"x"</span>: <span class="hljs-string">"@Official_R_deep"</span>,
    <span class="hljs-attr">"linkedin"</span>: <span class="hljs-string">"officalrajdeepsingh"</span>
  }
}
</code></pre>
<h3 id="heading-seo">SEO</h3>
<p>The SEO option configures the SEO settings for your documentation. The noindex option tells search engines not to index your documentation, and it defaults to false.</p>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
  noindex: <span class="hljs-literal">true</span>
}
</code></pre>
<h3 id="heading-search">Search</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909928336/a85c4f21-712d-4096-be08-15d605668a68.png" alt="configuration of the search in your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>To enable search functionality on your documentation site, you can integrate Algolia DocSearch by configuring the docsearch object in your <code>docs.json</code> file like this:</p>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
 <span class="hljs-attr">"search"</span>: {
    <span class="hljs-attr">"docsearch"</span>: {
      <span class="hljs-attr">"appId"</span>: <span class="hljs-string">"YOUR_APP_ID"</span>,
      <span class="hljs-attr">"apiKey"</span>: <span class="hljs-string">"YOUR_API_KEY"</span>,
      <span class="hljs-attr">"indexName"</span>: <span class="hljs-string">"YOUR_INDEX_NAME"</span>
    }
  }
}
</code></pre>
<h3 id="heading-tabs">Tabs</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909877477/9248bfa7-ed16-4d2a-9d2a-6624d4690123.png" alt="configuration of the tab in your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Tabs are an array of objects displayed at the top of your documentation website.</p>
<h4 id="heading-properties-1">Properties</h4>
<p>Each Tab object includes the following properties:</p>
<ul>
<li><p>id (string, required): A unique identifier for the tab.</p>
</li>
<li><p>title (string, required): The text label displayed on the tab.</p>
</li>
<li><p>href (string, required): The URL to navigate to when the tab is clicked.</p>
</li>
<li><p>locale (string, optional): If set, this tab is displayed only when viewing documentation for the specified locale.</p>
</li>
</ul>
<p>Here’s an example of a couple tabs:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"tabs"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"root"</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Documentation"</span>,
      <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-string">"components"</span>,
      <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Components"</span>,
      <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/components"</span>
    }
  ],
}
</code></pre>
<h3 id="heading-sidebar">Sidebar</h3>
<p>To display the sidebar on your website, you can configure or define it in the <code>docs.json</code> file your documentation, which will appear in the sidebar of your site.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745911338226/f3404a5d-b715-4e26-97c9-ce8169fe8d6b.png" alt="configuration of the sidebar in your documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Essentially, a sidebar is a list of links that appears on the side of your documentation. You can organize links using groups and pages by providing an array of sidebar objects.</p>
<h4 id="heading-options">Options:</h4>
<ul>
<li><p>pages: The pages option takes a list of page links to display in the sidebar. It accepts the following options:</p>
<ul>
<li><p>title (required): The title of the sidebar item.</p>
</li>
<li><p>href (required): The URL to link to when the sidebar item is clicked.</p>
</li>
<li><p>icon (optional): The icon to display next to the sidebar item.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>group (string): The title of the group under which the sidebar item will be displayed. If not provided, the item will appear at the top level of the sidebar.</p>
</li>
<li><p>href (string): The URL the sidebar item will link to when clicked.</p>
</li>
<li><p>icon (string): The name of the icon to display next to the sidebar item.</p>
</li>
<li><p>tab (string): If set, the sidebar item will only be shown when a specific tab (matching the provided tab ID) is active.</p>
</li>
</ul>
<pre><code class="lang-json"><span class="hljs-comment">// docs.json</span>
{
<span class="hljs-attr">"sidebar"</span>: [
    {
      <span class="hljs-attr">"pages"</span>: [
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Overview"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"book"</span>
        },
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Configuration"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/configuration"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"gear"</span>
        }
      ]
    },
    {
      <span class="hljs-attr">"group"</span>: <span class="hljs-string">"Components"</span>,
      <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"grip"</span>,
      <span class="hljs-attr">"pages"</span>: [
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Getting Started"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/components"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"rocket"</span>
        },
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Accordion"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/components/accordion"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"square-caret-down"</span>
        },
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Callouts"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/components/callouts"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"bullhorn"</span>
        },
        {
          <span class="hljs-attr">"title"</span>: <span class="hljs-string">"Cards"</span>,
          <span class="hljs-attr">"href"</span>: <span class="hljs-string">"/components/cards"</span>,
          <span class="hljs-attr">"icon"</span>: <span class="hljs-string">"square-full"</span>
        }
      ]
    }
  ]
}
</code></pre>
<p>If you want to learn more about this, check out the <a target="_blank" href="https://use.docs.page/configuration#sidebar">documentation here</a>.</p>
<h2 id="heading-how-to-use-pre-built-components-in-docspage">How to Use Pre-built Components in docs.page</h2>
<p>docs.page comes with <a target="_blank" href="https://use.docs.page/components">15 pre-built components</a>, so you don't need to import components into your MDX file. You can use them directly in your MDX file.</p>
<p>In the following example, I’m using the Info Callout component directly within the MDX file, without importing it.</p>
<pre><code class="lang-markdown"><span class="hljs-section">// index.mdx
---</span>
title: Welcome to docs.page!
<span class="hljs-section">description: Get started with docs.page
---</span>

Welcome to docs.page! The init command you just ran has created a basic file struture in your project to help you get started.

<span class="hljs-section">## Walkthrough</span>

<span class="hljs-section">### Configuration</span>

In the root of your directory a new <span class="hljs-code">`docs.json`</span> file has been created. This file is used to configure your documentation site. You can customize the name, description, and sidebar, theme, logos and more using this file.


<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Info</span>&gt;</span></span>Here's a basic example of what the file looks like: <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">Info</span>&gt;</span></span>
</code></pre>
<h2 id="heading-how-to-diagnose-errors-in-docspage">How to Diagnose Errors in docs.page</h2>
<p>If you encounter any errors on your documentation website, you can view all the errors by clicking the diagnostics button.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745863994785/16ec2f9a-86e6-4808-abdb-73513a54d428.png" alt="diagnosing the error in docs.page" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-use-frontmatter">How to Use Frontmatter</h2>
<p>Front matter is a block of YAML placed at the beginning of a Markdown file, enclosed between triple-dash <code>(---)</code> lines.</p>
<p>Frontmatter is a way to customise the metadata page directly within your Markdown files, and most importantly, frontmatter is used for SEO.</p>
<pre><code class="lang-markdown"><span class="hljs-section"># docs/getting-started.mdx</span>
---
title: Welcome to Awesome Project
<span class="hljs-section">description: Some awesome docs!
---</span>

<span class="hljs-section"># Welcome!</span>
</code></pre>
<p>Below is a list of some of the <a target="_blank" href="https://use.docs.page/frontmatter">important frontmatter properties</a> in docs.page, including their type and default values:</p>
<ul>
<li><p><code>title</code> (string): The page’s title used in metadata, social cards, and displayed as the main heading.</p>
</li>
<li><p><code>description</code> (string): A summary of the page appears in metadata for SEO and link previews.</p>
</li>
<li><p><code>image</code> (string): URL of an asset used in social cards and (if enabled) shown at the top of the page.</p>
</li>
<li><p><code>redirect</code> (string): A URL to forward visitors to. When set, the page’s content is bypassed.</p>
</li>
<li><p><code>showPageTitle</code> (boolean): Toggle whether the page title appears as a heading at the top.</p>
</li>
<li><p><code>showPageImage</code> (boolean): Toggle whether the front-matter image is rendered at the top.</p>
</li>
<li><p><code>noindex</code> (boolean): If true, instructs search engines not to index the page.</p>
</li>
</ul>
<p><a target="_blank" href="https://use.docs.page/frontmatter">Refer to the documentation</a> for more detail and other frontmatter property information.</p>
<h2 id="heading-how-to-add-assets-to-your-docs">How to Add Assets to Your Docs</h2>
<p>You can include assets, such as images and videos, in your documentation. You can add both remote and local assets.</p>
<h3 id="heading-remote-assets">Remote Assets</h3>
<p>To add remote assets to your documentation, you can reference them directly in your markdown files.</p>
<p>For example, to include an image from a URL:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># getting-started.mdx</span>
---
title: Welcome to get started
<span class="hljs-section">description: Some awesome docs!
---</span>

<span class="hljs-section"># Welcome!</span>

![<span class="hljs-string">Natural</span>](<span class="hljs-link">https://cdn.pixabay.com/photo/2023/04/19/19/11/lake-7938396_960_720.jpg</span>)
</code></pre>
<h3 id="heading-local-assets">Local Assets</h3>
<p>To use local assets in your documentation, create an <code>assets</code> folder inside the <code>docs/</code> directory. Then, add images and videos to the assets folder and reference them in your Markdown files.</p>
<p>Check out the following to better understand:</p>
<pre><code class="lang-bash">docs/
  assets/
    natural.png
  index.mdx
</code></pre>
<p>Within your markdown file, you can reference the image using a relative path:</p>
<pre><code class="lang-markdown">![<span class="hljs-string">Description</span>](<span class="hljs-link">/assets/natural.png</span>)
</code></pre>
<h3 id="heading-different-between-local-vs-remote-assets">Different between Local vs Remote Assets</h3>
<p>Local assets (PNG, JPG, PDF, and so on) are files stored within your project's public folder, while remote assets are files hosted on an external server. You can access your local assets using your domain URL.</p>
<pre><code class="lang-markdown">![<span class="hljs-string">Natural</span>](<span class="hljs-link">./assets/logo.png</span>)
</code></pre>
<p>On the other hand, remote assets are stored on a different server (image hosting), as I mentioned. You can access remote assets with a full URL.</p>
<p>The best examples of remote assets include images from Unsplash, Pixabay, and Pexels that can be used directly in your MDX file.</p>
<pre><code class="lang-markdown">![<span class="hljs-string">Natural</span>](<span class="hljs-link">https://images.unsplash.com/photo-1728044849236-5e8a061e1895</span>)
</code></pre>
<p>You can use remote and local assets based on your requirements – both have advantages and disadvantages. With remote assets, you can add an image directly in your mdx file. When using local assets, you add an image to the public folder and then reference it in your mdx file.</p>
<h2 id="heading-how-to-publish-your-documentation-website">How to Publish Your Documentation Website</h2>
<p>With docs.page, you can easily publish your documentation website. No configuration is required – once your documentation website is ready, you can just push your local code to a GitHub repository.</p>
<p>You can now access your documentation website immediately via the docs.page domain.</p>
<p>For example, if your GitHub repository is officialrajdeepsingh/docs-page-demo, your documentation will be available at <a target="_blank" href="https://docs.page/officialrajdeepsingh/docs-page-demo">https://docs.page/officialrajdeepsingh/docs-page-demo</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745849817613/c1b7b095-121d-4b64-bd7b-a834ca87f8b5.png" alt="publish your documentation website" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-live-preview-upcoming-changes-to-your-docs-website">How to Live Preview Upcoming Changes to Your Docs Website</h2>
<p>You can view previews of upcoming changes to your documentation before going public. As your documentation website grows, use the <a target="_blank" href="https://github.com/apps/docs-page">docs.page Github app</a> – any pull request you create in your Github repository automatically generates a unique live preview URL.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746278906018/0a299083-ff0a-4aea-a94e-95f94741e9af.png" alt="0a299083-ff0a-4aea-a94e-95f94741e9af" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>To configure the docs page of the GitHub application in your repository, follow these steps:</p>
<ol>
<li><p>Go to <a target="_blank" href="https://github.com/apps/docs-page">https://github.com/apps/docs-page</a></p>
</li>
<li><p>Click on the install button.</p>
</li>
<li><p>Select the GitHub account</p>
</li>
<li><p>Select All and single repository.</p>
</li>
<li><p>Click on the install button</p>
</li>
<li><p>Next, enter the password and OTP.</p>
</li>
<li><p>Now if your application is successful, install it in your repository.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746280111575/06d449cd-917a-4908-8d5e-db90cffd3c0f.gif" alt="Creates live previews in your github repository" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Whenever you or another developer create a pull request in your repository, the docs page application creates live previews for you.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>docs.page is a free, open-source project that allows you to create instant, fast, and beautiful documentation without requiring any configuration.</p>
<p>I think docs.page offers the best solution for documentation. You can easily set up and deploy your documentation website with the help of docs.page cloud service.</p>
<p>For now, it’s completely free to deploy a documentation website with a <a target="_blank" href="http://docs.page">docs.page</a>, and I hope it stays that way.</p>
<p>If <a target="_blank" href="http://docs.page">docs.page</a> ever decides to charge for their services, that could be troublesome. Hopefully, in that case, they’ll provide a clear guide on how to deploy your website on another cloud platform.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Good API Documentation ]]>
                </title>
                <description>
                    <![CDATA[ Imagine purchasing a standing fan straight out of the box, all parts dismantled, and you have no manual or guide to put them together. Did you imagine that just now? Cool. Here is another scenario: imagine purchasing an LG product, such as a smart TV... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-good-api-docs/</link>
                <guid isPermaLink="false">68151f0be5850fcb8543375a</guid>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ api documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okoro Emmanuel Nzube ]]>
                </dc:creator>
                <pubDate>Fri, 02 May 2025 19:37:47 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746108055356/29f327c1-60a5-4d0c-baef-431c0e61c1b4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine purchasing a standing fan straight out of the box, all parts dismantled, and you have no manual or guide to put them together. Did you imagine that just now? Cool.</p>
<p>Here is another scenario: imagine purchasing an LG product, such as a smart TV without a guide on how to set it up and use the remote. Now you get the point.</p>
<p>The process of you trying to mount your fan or set up your smart TV will be a very frustrating and confusing one without any guidance. And most of the time, it’ll be hard to determine the full potential of the product you bought.</p>
<p>Now, keeping in mind the already painted scenarios, have you ever tried picking up a new programming language or using an unfamiliar API, only to find it confusing, and you felt completely overwhelmed at the beginning? Then you probably spent hours trying to piece things together, maybe via tutorials, but nothing seems to work perfectly due to the error messages you get…and you wonder if you’re doing the right thing.</p>
<p>But then you might have come across the product’s official documentation or maybe a properly written and well-structured guide (like this one you’re reading). Suddenly, everything clicks, you start writing code effortlessly or using the API with confidence. That’s it – the power of clear and concise documentation.</p>
<p>In this article, you will learn what an API is, how it works, what API documentation is all about, and how to create standard API documentation.</p>
<p>Let’s dive in.</p>
<h2 id="heading-outline">Outline</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-an-api">What is an API</a>?</p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-apis-work">How APIs Work</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-apis">Types of APIs</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-api-documentation">What is API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-examples-of-api-documentation">Examples of API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-of-clear-api-documentation">Benefits of Clear API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-importance-of-a-clear-api-documentation">Importance of a Clear API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-notes-of-api-documentation">Key Notes of API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-component-of-an-api-documentation">Key Component of an API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-writing-concise-api-documentation">Best Practices for Writing Concise API Documentation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<p>Before we continue, let’s deviate a bit to learn what APIs are all about, how they work, and the types of APIs that are out there.</p>
<h2 id="heading-what-is-an-api"><strong>What is an API?</strong></h2>
<p>You might have heard the term API before, and you’re wondering what it’s all about. API stands for Application Programming Interface. An API acts as an interface between two programs that allows them to communicate. It is a mediator between the client (browsers/mobile application) and the server (backend).</p>
<h3 id="heading-how-apis-work"><strong>How APIs Work</strong></h3>
<p>So now you know that an API acts as a bridge or middleman that allows two systems to communicate with each other. When working with APIs, you’ll come across two key terms: <strong>requests</strong> and <strong>responses.</strong> These two keywords are essential to understand because they form the core of how APIs work.</p>
<p>Think of requests and responses like what you use in a regular day-to-day conversation. It’s just like how you ask questions (request) and an answer is provided (response). Same thing happens with APIs, but in this case, its an interaction between software systems.</p>
<p>To explain better how an API works, let’s use a weather app or a stock market app. This should provide a clear view of what we are talking about.</p>
<p>When you open a weather app and want to check the current weather, the app doesn’t store the weather data itself. Instead, it sends a request through an API to the weather database server. When the request is sent, the API now interacts/communicates with the database server and retrieves the latest weather information, which is then sent back to the weather app as a response. Then this info is finally displayed to you.</p>
<p>This should be a smooth, fast, and continuous process and has to occur simultaneously for your app to run smoothly. This means that a request must be made first before a response can be received. You can’t get a response without making a request.</p>
<p>The same process occurs for the stock market app as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745908659843/7aaad1e5-a18d-43fc-a74c-a416b9e19ce2.png" alt="Image of How an API works" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-types-of-apis"><strong>Types of APIs</strong></h3>
<p>APIs are categorised into two major types:</p>
<ul>
<li><p>By Use/Function</p>
</li>
<li><p>By Access</p>
</li>
</ul>
<h4 id="heading-types-of-apis-by-use"><strong>Types of APIs by Use</strong></h4>
<ul>
<li><p><strong>Web APIs</strong>: These are the most commonly used type of APIs and are also known as HTTP (Hypertext Transfer Protocol) APIs. This API enables communication over the internet with the use of HTTP. Examples of these APIs are REST APIs, GraphQL APIs, and so on.</p>
</li>
<li><p><strong>Library or Framework APIs</strong>: These are APIs provided by libraries or frameworks and are made use of by developers to build applications without having to build everything from scratch. Examples of this are React, JQuery, and so on.</p>
</li>
<li><p><strong>Operating System APIs</strong>: These are APIs built to allow systems/applications to communicate with operating systems. These APIs helps provide access to system-level resources, which is important for the application to function properly. Examples of these APIs are Android SDK, Windows API, and so on.</p>
</li>
<li><p><strong>Hardware APIs</strong>: These are APIs built to enable systems to communicate with the physical components of a hardware device. Examples of these APIs are Bluetooth APIs, Camera APIs, and so on.</p>
</li>
<li><p><strong>Database APIs</strong>: Just as the name states, they are APIs that allow applications to interact with the database. These APIs are essential and mostly used to store, retrieve, manage and update the database. Examples of these APIs are SQL-based APIs, NoSQL APIs, and so on.</p>
</li>
</ul>
<h4 id="heading-types-of-apis-by-access"><strong>Types of APIs by Access</strong></h4>
<ul>
<li><p>Open APIs: This can be seen as a public API and is also referred to as an external APIs. These are the types of APIs built and made available for anyone to use, therefore making them need little to no authorization and authentication. Based on the number of calls made to these APIs, some of them APIs are available for free while others are available at a specific cost (paid subscription).</p>
</li>
<li><p>Partner APIs: These are types of APIs built and made available for just businesses that collaborate together. When this type of APIs are built, strong authentication and authorization process are put into consideration so as to avoid it from being accessed by the public.</p>
</li>
<li><p>Internal APIs: The internal APIs can also be referred to as private APIs. These APIs are built and internally used by organization and are restricted from the public. These APIs are mostly used when there is communication between systems or Applications within the organization.</p>
</li>
<li><p>Composite APIs: This is a type of API built in a way that it combines multiple API requests into a bundle and allows users to get one single response from different servers. This type of APIs is most commonly used when Devs needs to fetch data from multiple servers or data sources.</p>
</li>
</ul>
<p>Now that we have broken down what APIs are, how they work, and their various types, let's move on to the main reason we’re here: learning about creating good API documentation.</p>
<h2 id="heading-what-is-api-documentation"><strong>What is API Documentation?</strong></h2>
<p>API documentation is also referred to as developer documentation. It is a well-written and organized guide or manual that explains how an API works. It’s designed to help developers (or even non-developers) understand what the API does, how to use it, and how to integrate it into their own projects.</p>
<p>By using API documentations, you can explore and take full advantage of everything an API has to offer. API documentation also aims at speeding up the development process and boosting the overall productivity of a product.</p>
<p>API documentation provides a detailed explanation of the complete functionality of the API, which can include:</p>
<ul>
<li><p>The most efficient way to use the API</p>
</li>
<li><p>How to integrate the API with your project.</p>
</li>
<li><p>The purpose of the API and the inputs to be passed for developers to make good use of it.</p>
</li>
</ul>
<h2 id="heading-examples-of-api-documentation"><strong>Examples of API Documentation</strong></h2>
<p>Here are some examples of API documentation to give you a better idea of what’s involved and what information these docs should provide.</p>
<h3 id="heading-stripe-api-docs"><strong>Stripe API Docs</strong></h3>
<p>This is an example of a Web/HTTP API. Stripe is a payment processing tool, and the <a target="_blank" href="https://docs.stripe.com/api">Stripe API documentation</a> provides a clean, interactive, and developer-friendly guide on how to make use of the API for payment integrations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745908370335/eb50afc2-30b8-41ba-8c53-fd47b0f643a4.png" alt="Stripe API documentation Image" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-react-docs"><strong>React Docs</strong></h3>
<p>The <a target="_blank" href="https://react.dev/learn">React docs</a> are an example of a library or framework API. They provide a detailed guide to how you can use React in building your web project</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745908586648/b366b340-004b-4b88-8d6e-ab8eab8b04c1.png" alt="React API documentation image" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-android-sdk"><strong>Android SDK</strong></h3>
<p>This is an example of an Operating System API. The <a target="_blank" href="https://developer.android.com/reference">Android SDK Documentation</a> provides a detailed guide on how you can make use of the Android SDK API to build your Android app.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745908800051/c0707d78-6d29-4bf8-ace4-fa07d38e58bd.png" alt="Andriod SDK API documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-web-bluetooth-api"><strong>Web Bluetooth API</strong></h3>
<p>This is an example of a hardware API. The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API">Web Bluetooth API Docs</a> provide a detailed guide on how to make use of the API to connect and interact with Bluetooth low energy peripherals.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909018248/70c028d5-5c70-4441-949d-a89b2ba9a183.png" alt="Web Bluetooth API Documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-postgresql-api">PostgreSQL API</h3>
<p>This is an example of a Database API. The <a target="_blank" href="https://www.postgresql.org/docs/current/libpq-connect.html">PostgreSQL API Docs</a> provide developers with full details on what the API is all about, how they can effortlessly connect it with their application, and also the roadblocks they can encounter while using the API and how to overcome them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909167138/3004c153-8a7a-4814-b824-31fca6d11433.png" alt="PostgreSQL API documentation" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-benefits-of-clear-api-documentation"><strong>Benefits of Clear API Documentation</strong></h2>
<h3 id="heading-enhances-the-developer-experience"><strong>Enhances the Developer Experience</strong></h3>
<p>Great API documentation makes a developer’s life much easier. It clearly explains what the API does, how it works, and how to use it – all of which help developers get up to speed quickly.</p>
<p>Instead of wasting time figuring things out or getting stuck, they can focus on building. It reduces frustration, boosts productivity, and even makes it easier to collaborate with teammates.</p>
<h3 id="heading-reduces-the-learning-curve"><strong>Reduces the Learning Curve</strong></h3>
<p>Good API documentation helps reduce the learning curve for developers trying to use the API. This, in turn, leads to faster onboarding, saves time and money, and encourages higher adoption rates.</p>
<h3 id="heading-easy-to-maintain"><strong>Easy to Maintain</strong></h3>
<p>Good API documentation makes it easier to maintain both the API and any application the API is used in. Up-to-date docs help developers understand changes, fix bugs, and update features in their application with confidence.</p>
<h3 id="heading-provides-visibility-for-your-product"><strong>Provides Visibility for Your Product</strong></h3>
<p>Good API documentation increases the visibility of your product and encourages frequent use by making it easier for developers to understand and integrate it. It also promotes third-party integration, helping your product reach a wider audience.</p>
<h2 id="heading-key-components-of-api-documentation"><strong>Key Components of API Documentation</strong></h2>
<p>There are many components that make up a good API documentation. In this section, we will walk through a real-world example of properly prepared API documentation: the Spotify Web API.</p>
<h3 id="heading-overviewdescription-and-uses-of-the-api"><strong>Overview/Description and Uses of the API</strong></h3>
<p>This is the very first stage in writing good API documentation. This section explains to users what the API is all about and also has information about the type of resources it provides.</p>
<p>The overview section is usually short, perhaps 3-4 sentences, and it describes what the API is does, the available resources, its endpoints, and the methods attached to each endpoint. This helps bring you up to speed as to whether that particular API provides what you need to complete your project.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909576601/ad916148-11df-4c8f-985e-8f9714173e04.png" alt="Overview Example of an API Doc's description section" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see, the Spotify API’s description explains how it helps you create applications that “can interact with Spotify’s streaming service, such as retrieving content metadata, creating and managing playlists, or controlling playback.”</p>
<h3 id="heading-endpoints"><strong>Endpoints</strong></h3>
<p>Endpoints are an important component in API documentation. Developers use them to communicate with other servers. They’re also used for data transfers. An Endpoint is referred to as the “touch point” in the communication channel between two servers.</p>
<p>When documenting an endpoint, it’s important to take note of the various components of the endpoints, as this increases the quality of your API documentation. The components of an endpoint include its <code>name</code>, <code>description</code>, <code>url</code>, <code>methods</code>, <code>parameters</code>, and so on.</p>
<p>For example, if you want to get the details of a user’s top artist, here’s how the endpoint looks:</p>
<pre><code class="lang-javascript">GET https:<span class="hljs-comment">//api.spotify.com/v1/me/top/artists</span>
</code></pre>
<p>Remember, we previously mentioned the key components that make up an API endpoint, such as the name, description, URL, and HTTP method. Let's take the Spotify endpoint URL above to see how these components are presented:</p>
<ul>
<li><p><strong>Name:</strong> Get User's Top Artists</p>
</li>
<li><p><strong>Description:</strong> Retrieves the current user's most listened-to artists.</p>
</li>
<li><p><strong>URL:</strong> <a target="_blank" href="https://api.spotify.com/v1/me/top/artists"><code>https://api.spotify.com/v1/me/top/artists</code></a></p>
</li>
<li><p><strong>Method:</strong> <code>GET</code></p>
</li>
</ul>
<p>This endpoint demonstrates how a well-documented API provides all the necessary details a developer needs to understand and use it effectively.</p>
<p>Response:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"rank"</span>: <span class="hljs-number">1</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Eminem"</span>,
 },

{
  <span class="hljs-attr">"rank"</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"NF"</span>,
 },

{
  <span class="hljs-attr">"rank"</span>: <span class="hljs-number">3</span>,
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Adele"</span>,
 },
</code></pre>
<p>Now the code above indicates the response I should get from my initial request and it is displayed in a JSON format.</p>
<h3 id="heading-authorization-and-authentication"><strong>Authorization and Authentication:</strong></h3>
<p>Both authorization and authentication are important tools used for checking the access that’s been given to sensitive data.</p>
<p>APIs receive thousands of responses and handle huge amounts of data. Authentication and Authorization are ways to ensure that your API data and your users are safe and secure from hackers.</p>
<p>Note that authentication and authorization are two different concepts. Authentication is mainly all about verifying the identity of someone who wants to use your API. Authorization, on the other hand, describes the level of access that an already verified user has when interacting with the API.</p>
<p>There are three major types of API Authentication. Each type is used at different stages or levels, but in some scenarios, no authentication is used at all.</p>
<ul>
<li><p><strong>Basic Authentication:</strong> This is the type of API auth that is usually used for testing internal APIs. It’s not recommended for publicly used APIs because it’s not fully secure. This API sends a username and password with every API call made to the client.</p>
</li>
<li><p><strong>Key Authentication:</strong> In this type of auth, the client generates and sends a very long key. The API key is a long string that contains unique authorization tokens. This type of auth is more secure than the basic auth – but if the key is leaked, anyone can access the API until it’s revoked. Note: This type of Authentication is used for light applications.</p>
</li>
<li><p><strong>OAuth Authentication:</strong> OAuth is the most common and more secure token-based type of authentication. In this type of authentication, instead of sending a username and password, an authorization is first requested, which is approved by the user. After the user approves the request, a token is generated which can be used to make an API request. This method is secure, and the tokens generated have an expiration time as well.</p>
</li>
</ul>
<p>Let’s look at an example from the Spotify API.</p>
<p>Spotify uses <strong>OAuth 2.0</strong> for authentication and access control. To use most of Spotify’s Web API endpoints, you must first authenticate your application and obtain permission from the user:</p>
<pre><code class="lang-javascript">GET https:<span class="hljs-comment">//accounts.spotify.com/authorize</span>
</code></pre>
<p>Here are the key details of the Authorization endpoint:</p>
<ul>
<li><p><strong>Name:</strong> Authorization</p>
</li>
<li><p><strong>Description:</strong> Initiates the OAuth 2.0 flow to authorize users and allow your application to access Spotify data on their behalf.</p>
</li>
<li><p><strong>URL:</strong> <a target="_blank" href="https://accounts.spotify.com/authorize"><code>https://accounts.spotify.com/authorize</code></a></p>
</li>
<li><p><strong>Method:</strong> <code>GET</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1745909858569/5785d44b-642b-400c-b3b5-c12508faac43.png" alt="Sportify Authentication and Authorization Image" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-parameters-and-headers"><strong>Parameters and Headers:</strong></h3>
<p>Parameters are the variable part of a resource and comprise a name, value, and description. Some parameters are required and are used in making API calls, while some are just optional.</p>
<p>When writing an API documentation, you should list out all the parameters and descriptions alongside each parameter. It’s also a good idea to specify why such a parameter is needed and state if it is required or optional in the documentation.</p>
<p>Headers, on the other hand, are similar to parameters. They have key-value pairs and are used to send additional information (metadata) about a request to the server. If there are any headers used in your API, then it is important you include them when documenting the API.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746181055214/dbf02273-71ef-472e-94d1-7b49c78f9751.png" alt="Parameters and headers" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>As you can see in the image above, we have some Body Parameters and Header Parameters. For body parameters, there’s <code>grant_type</code> (which is required), <code>code</code> (also required), and <code>redirect_uri</code> (also required). You can also see that they have descriptions of the value listed.</p>
<p>For header parameters, we have <code>Authorization</code> (required) and <code>Content-Type</code> (also required), again with descriptions of their values.</p>
<h3 id="heading-error-handling-codes-and-troubleshooting-guidance"><strong>Error Handling Codes and Troubleshooting Guidance:</strong></h3>
<p>Errors are inevitable, they’ll always occur despite how careful you are. That’s why good API documentation should include guidance to help developers recover quickly when things go wrong.</p>
<p>Your documentation should provide a section that;</p>
<ul>
<li><p>Suggest possible fixes or troubleshooting tips for some specific errors.</p>
</li>
<li><p>Include sample error response codes and logs, which help in debugging.</p>
</li>
</ul>
<p>When it comes to API calls, two key components to understand are the <strong>request</strong> and the <strong>response</strong>. When an API call is made, a request is sent to the server, and a response is returned. This response includes a <strong>status code</strong> and, if applicable, an <strong>error code</strong> and both are essential for understanding what happened during the request.</p>
<p>For example, there are situations when you make an API call and the response you get is a code 404, which means that the request you made was not found. But when things go smoothly, you should see a code 200, which means your request was successful.</p>
<p>Here is what this section looks like:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"error"</span>: {
    <span class="hljs-attr">"status"</span>: <span class="hljs-number">404</span>,
    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Not Found"</span>
  }
}
</code></pre>
<p>By properly documenting these status and error codes with their explanations, developers can easily identify issues and take appropriate actions to solving it those issues.</p>
<p>Here are some common Response Code Statuses and what they mean:</p>
<h4 id="heading-response-code-status">Response Code Status:</h4>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Status Code</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>200</td><td>OK</td></tr>
<tr>
<td>201</td><td>Created</td></tr>
<tr>
<td>202</td><td>Accepted</td></tr>
<tr>
<td>400</td><td>Bad Request</td></tr>
<tr>
<td>401</td><td>Unauthorized</td></tr>
<tr>
<td>403</td><td>Forbidden</td></tr>
<tr>
<td>404</td><td>Not Found</td></tr>
<tr>
<td>500</td><td>Internal Server Error</td></tr>
<tr>
<td>502</td><td>Bad Gateway</td></tr>
<tr>
<td>503</td><td>Service Unavailable</td></tr>
</tbody>
</table>
</div><p>The table above shows some of the most common code response statuses you’ll come across when using an API and its description.</p>
<h2 id="heading-best-practices-for-writing-concise-api-documentation"><strong>Best Practices for Writing Concise API Documentation</strong></h2>
<p>Here are some best practices that can help guide you while writing API documentation:</p>
<ol>
<li><p>You want to make sure users clearly understand what the API is, how they can use it, and the limits of use for the API.</p>
</li>
<li><p>Know your target audience and focus on what they need most to get started with the API docs.</p>
</li>
<li><p>Always stick to the essential information and use clear and consistent language.</p>
</li>
<li><p>Structure your documentation properly and make it standard.</p>
</li>
<li><p>Examples are important. Always use them in your documentation and make sure you clearly explain them.</p>
</li>
<li><p>Avoid repetition in your documentation.</p>
</li>
<li><p>Always document your error codes clearly. It’s recommended that you put them in tabular format.</p>
</li>
<li><p>Always provide a link to outsourced files in situations when more details are needed. This helps keep your documentation short and on point.</p>
</li>
<li><p>Review and regularly update the documentation.</p>
</li>
<li><p>Incorporate user feedback for continuous improvement.</p>
</li>
</ol>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>API documentation has become a critical component in today's technology landscape. Clear and concise documentation is not just helpful – it’s essential. It often determines whether an API succeeds in the tech ecosystem and whether developers can fully leverage its power.</p>
<p>This is a call to action for developers, organizations, and technical writers: prioritize high-quality, well-structured API documentation. The clarity of your documentation directly impacts the usability, adoption, and long-term success of your product in the industry.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Documentation as Code with Docusaurus and GitHub Actions ]]>
                </title>
                <description>
                    <![CDATA[ For technical writers, keeping documentation up to date manually can be really frustrating. Issues like outdated guides, broken links, and missing updates are a pain, and they can make writers less productive. These issues can also make it harder for... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/set-up-docs-as-code-with-docusaurus-and-github-actions/</link>
                <guid isPermaLink="false">67a39f467e716749ae8c7b7e</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ docs-as-code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ docusaurus ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ github-actions ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ EZINNE ANNE EMILIA ]]>
                </dc:creator>
                <pubDate>Wed, 05 Feb 2025 17:26:30 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738248926082/9a2a6855-00d4-4e25-a8bd-c1d645f21de5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For technical writers, keeping documentation up to date manually can be really frustrating. Issues like outdated guides, broken links, and missing updates are a pain, and they can make writers less productive. These issues can also make it harder for people to effectively use the docs and get correct information.</p>
<p>Documentation as code, or docs as code, is an approach to managing documentation that treats the docs like a codebase. It lets you version, automatically update, and review your docs just like you would do in a codebase. Docs as code helps you make sure that your docs are up to date and that users can gain access to accurate information.</p>
<p>This tutorial will show you how to:</p>
<ul>
<li><p>Create a documentation website using Docusaurus.</p>
</li>
<li><p>Track changes with Git and GitHub.</p>
</li>
<li><p>Build and deploy it to a hosting platform.</p>
</li>
<li><p>Set up a workflow to perform grammatical reviews using GitHub Actions before you merge your changes.</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This tutorial is beginner-friendly, but there are some tools you’ll need to have or know in order to follow along:</p>
<ul>
<li><p><a target="_blank" href="https://code.visualstudio.com/download">VSCode IDE (or other IDE of your choice)</a>.</p>
</li>
<li><p><a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">Node.js and npm installed.</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/">A GitHub account.</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/gitting-things-done-book/">A reasonable knowledge of how to use Git and GitHub.</a></p>
</li>
</ul>
<h2 id="heading-why-do-technical-writers-use-docs-as-code">Why Do Technical Writers Use Docs as Code?</h2>
<p>Before we dive in, let’s quickly talk about what "docs as code" is and why it matters. Back in 2015, two technical writers at Google came up with the idea to make it easier for developers to contribute to documentation and to better organize their company documents. There were times when they needed to write about an application they were working on, but things were really disorganized. So they came up with this process. Since then, many companies have adopted the approach.</p>
<p>Docs as code is now a popular approach to managing documentation, and it’s supported by many tools that are designed to treat documentation like code. Tom Johnson explains this concept in more detail in <a target="_blank" href="https://idratherbewriting.com/learnapidoc/pubapis_docs_as_code.html">his article on docs as code</a>.</p>
<p>Traditional documentation relies on Word documents and PDFs, where changes are tracked manually or through document revision history. Writers must update and publish content manually, with no way to automate routine tasks.</p>
<p>On the other hand, docs as code borrows principles and tools from software development to make documentation more structured, versioned, and automated. The documentation is stored in version control (like Git), written in lightweight markup languages, and gets updated alongside the code.</p>
<p>This approach ensures that documentation evolves alongside the software, maintains high quality, and allows for efficient collaboration, just like writing code.</p>
<h3 id="heading-tools-well-use-in-this-tutorial">Tools We’ll Use in This Tutorial</h3>
<p>Let’s review the main tools we’ll be using for this tutorial:</p>
<ol>
<li><p>Docusaurus is a tool created by Facebook for creating documentation websites. It supports markdown and mdx. It also supports versioning and custom themes, making it easy to create user-friendly and professional docs.</p>
</li>
<li><p>Vale is a customizable style and grammar checker for writers. It ensures consistent language, tone, and style across technical documents. There are other good linters you could use for review apart from Vale, but that’s what we’ll be using here.</p>
</li>
<li><p>GitHub Actions: A CI/CD tool for automating workflows directly in GitHub. It helps you test, build, and deploy code with ease.</p>
</li>
</ol>
<h2 id="heading-step-1-install-docusaurus">Step 1: Install Docusaurus</h2>
<p>Open your command line terminal and enter the following:</p>
<pre><code class="lang-javascript">npx create-docusaurus@latest docs-<span class="hljs-keyword">as</span>-code-tutorial classic
</code></pre>
<p><code>docs-as-code-tutorial</code> is the name I am using for the site. You can replace it with any other site name if you wish. Select JavaScript as the language you want to use. This will begin to create a new Docusaurus site. After running the code, you’ll see the <code>docs-as-code-tutorial</code> folder in your VSCode workspace. Navigate to the folder.</p>
<p>Next, start the development server so you can see your docs.</p>
<pre><code class="lang-javascript">cd docs-<span class="hljs-keyword">as</span>-code-tutorial
npm start
</code></pre>
<p>With this, the site will start running at <code>localhost:3000</code>.</p>
<p>When you view the site, you’ll see pre-generated content. So, in the next step, you’ll to create a repository and link the local folder to your remote repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737868185569/0cf96b6c-770a-4965-b017-1fe54796c673.png" alt="the docusaurus homepage" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-2-create-a-repository">Step 2: Create a Repository</h2>
<p>Now, you need to create a repository for the <code>docs-as-code-tutorial</code>. So go to your GitHub account and create a new repository.</p>
<p>After creating the repository, you’ll need to link the repository to the folder in your VSCode workspace.</p>
<p>Open a new terminal and run these commands:</p>
<pre><code class="lang-javascript">git init
git add .
git commit -m <span class="hljs-string">"first commit"</span>
git branch -M main
git remote add origin https:<span class="hljs-comment">//github.com/myname/docs-as-code-tutorial.git</span>
git push -u origin main
</code></pre>
<p>With that, you have linked the repository, and Git will start tracking your changes.</p>
<h2 id="heading-step-3-customize-your-docs-in-the-docusaurusconfig-file">Step 3: Customize your Docs in the <code>docusaurus.config</code> File</h2>
<p>Before you begin customizing, create a branch where you can make your changes as you push it to the main branch.</p>
<pre><code class="lang-powershell">git checkout <span class="hljs-literal">-b</span> <span class="hljs-string">"new_branch"</span>
</code></pre>
<p>The <code>docusaurus.config.js</code> file is where you can make most of the edits to your site. Change the <code>title</code> property to <code>Docs as code</code>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> config = {
  <span class="hljs-attr">title</span>: <span class="hljs-string">'Docs as code'</span>,
  <span class="hljs-attr">tagline</span>: <span class="hljs-string">'Documentation as code'</span>,
<span class="hljs-comment">//rest of your code</span>
   <span class="hljs-attr">navbar</span>: {
        <span class="hljs-attr">title</span>: <span class="hljs-string">'Docs as code'</span>,
<span class="hljs-comment">//rest of your code</span>
  }
}
</code></pre>
<p>That will show as the new title when you preview the docs. This is simply an illustration to display how Docusaurus works. You can further customize the site to your desired style, but we won’t go into more detail on that here (as the main purpose of this tutorial is to show how to set up your docs as code).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737869529640/c4dab104-9f8b-4dad-a3a5-250d15d4552d.png" alt="c4dab104-9f8b-4dad-a3a5-250d15d4552d" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>After making the changes, the site should look a bit different.</p>
<p>You can push the changes now.</p>
<pre><code class="lang-powershell">git commit <span class="hljs-literal">-am</span> <span class="hljs-string">"first commit"</span>
git push -<span class="hljs-literal">-set</span><span class="hljs-literal">-upstream</span> origin new_branch
</code></pre>
<h2 id="heading-step-4-edit-your-docs">Step 4: Edit Your Docs</h2>
<p>For this tutorial, I’ll be making edits in the <code>docs</code> section. Go to <code>intro.md</code> and replace the markdown text with this writeup:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># How to set up docs-as-code</span>

Documentation-as-code is a great means to push changes made in your local machine to your docs live site. To accomplish this, you need an IDE, a static site generator, a Git repository, CI/CD to set up workflows, and a hosting platform. 

<span class="hljs-section">## Why do technical writers do docs-as-code?</span>

Documentation-as-code is a great means to push changes made in your local machine to your docs live site. To accomplish this, you need an IDE, a static site generator, a Git repository, CI/CD to set up workflows, and a hosting platform.
</code></pre>
<p>After making the edits, preview your docs.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737870301247/dba83233-a11c-4ec0-aeaf-b11e525ca090.png" alt="intro.md displaying the writeup " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-5-add-the-linting-feature">Step 5: Add the Linting Feature</h2>
<p>Add the Vale linter to your docs to review errors. To do that, install the Vale CLI with any of these commands.</p>
<ul>
<li><p>Run <code>choco install vale</code> for Windows</p>
</li>
<li><p><code>brew install vale</code> for MacOs, or</p>
</li>
<li><p><code>snap install vale</code> for Linux</p>
</li>
</ul>
<h3 id="heading-how-to-set-up-vale"><strong>How to set up Vale</strong></h3>
<p>As I mentioned earlier, Vale is a customizable style and grammer checking tool. This means you can set it up to review your docs exactly how you want.</p>
<p>Vale uses the Vale style guide when performing reviews to spot errors and make suggestions. But you can add your company’s style guide or any other style guide to it if you prefer. There are public style guides you can use like the Google style guide, Microsoft style guide, and so on. For this tutorial, we’ll be using the Microsoft style guide.</p>
<p>If you don’t already have it, you’ll need to <a target="_blank" href="https://github.com/errata-ai/Microsoft/releases/download/v0.7.0/Microsoft.zip">get the Microsoft style guide</a>, download it, and unzip it. Create a styles folder and move the Microsoft folder to the styles folder.</p>
<p>This should be your file path:</p>
<pre><code class="lang-javascript">- docs-<span class="hljs-keyword">as</span>-code-tutorial
  <span class="hljs-comment">//other folders</span>
  - styles
    - Microsoft
  <span class="hljs-comment">//other folders</span>
</code></pre>
<p>In your docs, create a <code>.vale.ini</code> file and add it to your root. </p>
<p>Add this code in it:</p>
<pre><code class="lang-plaintext">StylesPath = styles

MinAlertLevel = suggestion

[*.md]

BasedOnStyles = Vale, Microsoft
</code></pre>
<p>Let’s understand what’s going on here:</p>
<ul>
<li><p>The <code>StylesPath</code> is set to the styles folder where you added the Microsoft style guide you downloaded. The MinAlertLevel sets Vale alerts to <code>suggestion</code> – this means that Vale will highlight suggestions, warnings, and errors found in your docs. If the MinAlertLevel is set to errors, then Vale will highlight errors only. If set to warnings, then it’ll highlight warnings and errors (and so on).</p>
</li>
<li><p><code>[*.md]</code> tells Vale to go through <code>.md</code> files only.</p>
</li>
<li><p><code>BasedOnStyles</code> indicates which style guide you are using for the linting. In this case, it’s the Microsoft style guide and Vale style guide. So when the linter is running, it will highlight suggestions, warnings, and errors using the specified style guides.</p>
</li>
</ul>
<p>To test your docs, run <code>vale intro.md</code> (assuming you still have the <code>intro.md</code> file).</p>
<p>This should be the output:</p>
<pre><code class="lang-plaintext">✔ 0 errors, 0 warnings and 0 suggestions in stdin.
</code></pre>
<h2 id="heading-step-6-build-the-site">Step 6: Build the Site</h2>
<p>To do this, run <code>npm run build</code>. After that, you can preview the build with <code>npm run serve</code>.</p>
<h2 id="heading-step-7-deploy-the-site">Step 7: Deploy the Site</h2>
<p>There are different hosting platforms where you can host your live site. This tutorial covers two hosting options: GitHub Pages and Netlify.</p>
<h3 id="heading-deploy-with-github-pages"><strong>Deploy with GitHub Pages</strong></h3>
<p>To deploy to GitHub Pages, you’ll need to set your repository name and GitHub username/organization name in the <code>docusauraus.config.js</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Set the production url of your site here</span>

  <span class="hljs-attr">url</span>: <span class="hljs-string">'https://ezinneanne.github.io/'</span>,

  <span class="hljs-comment">// Set the /&lt;baseUrl&gt;/ pathname under which your site is served</span>

  <span class="hljs-comment">// For GitHub pages deployment, it is often '/&lt;projectName&gt;/'</span>

  <span class="hljs-attr">baseUrl</span>: <span class="hljs-string">'/docs-as-code-tutorial/'</span>,

  <span class="hljs-comment">// GitHub pages deployment config.</span>

  <span class="hljs-comment">// If you aren't using GitHub pages, you don't need these.</span>

  <span class="hljs-attr">organizationName</span>: <span class="hljs-string">'ezinneanne'</span>, <span class="hljs-comment">// Usually your GitHub org/user name.</span>

  <span class="hljs-attr">projectName</span>: <span class="hljs-string">'docs-as-code-tutorial'</span>, <span class="hljs-comment">// Usually your repo name.</span>
</code></pre>
<p>You can deploy the site to GitHub Pages in the following ways:</p>
<ul>
<li><p>Using the Powershell terminal with this command:</p>
<p>  <code>cmd /C 'set "GIT_USER=&lt;GITHUB_USERNAME&gt;" &amp;&amp; yarn deploy'</code> </p>
</li>
<li><p>Using the Windows Command line terminal with this command:</p>
<p>  <code>cmd /C "set "GIT_USER=&lt;GITHUB_USERNAME&gt;" &amp;&amp; yarn deploy"</code></p>
</li>
<li><p>Using Bash with this command:<br>  <code>GIT_USER=&lt;GITHUB_USERNAME&gt; yarn deploy</code></p>
</li>
</ul>
<p>Just make sure you replace <code>&lt;GITHUB_USERNAME&gt;</code> with your username on GitHub.</p>
<p>Voilà! The site is deployed at <a target="_blank" href="https://ezinneanne.github.io/docs-as-code-tutorial/">https://ezinneanne.github.io/docs-as-code-tutorial/</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737918709225/3eb12747-4a13-4c17-a7ad-ab6ee84b64ff.png" alt="the docs-as-code homepage deployed on Github Pages" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-deploy-with-netlify"><strong>Deploy with Netlify</strong></h3>
<p>To deploy to Netlify, you only need the production URL and base URL:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Set the production url of your site here</span>

  <span class="hljs-attr">url</span>: <span class="hljs-string">'https://docs-as-code-tutorial.netlify.app'</span>,

  <span class="hljs-attr">baseUrl</span>: <span class="hljs-string">'/'</span>,
</code></pre>
<ol>
<li><p>Go to your <a target="_blank" href="https://www.netlify.com/">Netlify account</a> and link your repository.</p>
</li>
<li><p>Click on <code>Add new site</code>.</p>
</li>
<li><p>Click on <code>import an existing project</code>.</p>
</li>
<li><p>Connect to your GitHub account and select the <code>docs-as-code-tutorial</code> repository.</p>
</li>
<li><p>Give your site a name, it should be the same as the URL in your <code>docusaurus.config.js</code>.</p>
</li>
<li><p>Add the publish directory which is <code>build</code> and the build command which is <code>npm run build</code>. Then Netlify will deploy to your default branch <code>main</code>, unless you specify otherwise.</p>
</li>
<li><p>Finally, deploy!</p>
</li>
</ol>
<p>You should see the site running at <a target="_blank" href="https://docs-as-code-tutorial.netlify.app/">https://docs-as-code-tutorial.netlify.app/</a>.</p>
<p>For other deployment options, <a target="_blank" href="https://docs-as-code-tutorial.netlify.app/">you can</a> <a target="_blank" href="https://docusaurus.io/docs/deployment">check out the Docusauraus documentation</a>.</p>
<h2 id="heading-step-8-set-up-a-documentation-workflow-using-github-actions">Step 8: Set Up a Documentation Workflow Using GitHub Actions</h2>
<p>Now we’ll set up a workflow for the documentation. In GitHub, when you deploy to GitHub Pages, it sets up a default workflow for you at <code>pages-build-deployments</code>.</p>
<p>Netlify also automates deployments but does not create a workflow file in your repository. Instead, it manages the process through its platform, monitoring your repository for changes and running builds based on your settings. In this tutorial, we will set up a workflow with GitHub Actions that automates Vale running linting checks through the docs.</p>
<p>Create a <code>.github/workflows</code> directory and add a <code>vale-linter.yml</code> file in it. </p>
<p>Add this code in it:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Vale</span> <span class="hljs-string">Lint</span> <span class="hljs-string">Checker</span>

<span class="hljs-comment"># Trigger the workflow on specific events.</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span> <span class="hljs-comment"># Run on every push to the main branch.</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">pull_request:</span> <span class="hljs-comment"># Run on pull requests targeting any branch.</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">'*'</span>
  <span class="hljs-attr">workflow_dispatch:</span> <span class="hljs-comment"># Allow manual triggering from the Actions tab.</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">prose:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># Step 1: Check out the repository code.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">Code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span> 

      <span class="hljs-comment"># Step 2: Set up Node.js</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Node.js</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-number">16</span> <span class="hljs-comment"># Use Node.js 16 or higher</span>

      <span class="hljs-comment"># Step 3: Run Vale lint checks.</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Vale</span> <span class="hljs-string">Lint</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">errata-ai/vale-action@reviewdog</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">files:</span> <span class="hljs-string">.</span>
        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">GITHUB_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span>
</code></pre>
<p>After making these changes, run the following commands:</p>
<pre><code class="lang-powershell">git add .
git commit <span class="hljs-literal">-m</span> “changes”
</code></pre>
<p>Finally push to the repository with <code>git push</code>.</p>
<p>Go to the <code>Actions</code> tab on your repository. You should see the workflow running:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737521586319/3d554246-f8e6-4885-bac5-2cead1b3dd56.png" alt="The github repository page with focus on the Actions tab showing the vale workflow" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Click on the <code>changes</code> button and click on the job <code>prose</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737970927236/632e2753-5d2e-474b-a05e-74a9affa634d.png" alt="A brief preview of the lint output from vale in the prose job run" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, you should see all the lines in your <code>.md</code> files highlighted by Vale.</p>
<p>With this, your docs are set up to run like a codebase! You can make changes, and when you push, review, and merge, it will sync automatically.</p>
<p>Keep in mind that this is for Netlify. For GitHub Pages, you’ll need to set up a workflow for automatic deployment.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this tutorial, you have learned how to set up documentation as code using Docusaurus. You also saw how to deploy your documentation to a live site, and automate the linting workflow with Vale and GitHub Actions.</p>
<p><a target="_blank" href="https://docs.github.com/en/actions/use-cases-and-examples/creating-an-example-workflow">There are other workflows</a> you can set up to ease the workload in managing your doc site. Remember, the main point is to organize and structure your docs while automating regular documentation practices using software development tools. This lets you focus on the most important thing which is creating quality content for your readers.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle Complex Use Cases in Your OpenAPI Specifications – API Documentation Guide ]]>
                </title>
                <description>
                    <![CDATA[ When you’re documenting an API reference, there are two main approaches you can follow. You can either use the manual approach of filling in the endpoints via a user interface, or organize a structured document containing all the necessary informatio... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-handle-complex-use-cases-in-api-specs/</link>
                <guid isPermaLink="false">6728f9e02b7cd4e7135f2f39</guid>
                
                    <category>
                        <![CDATA[ Technical writing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ OpenApi ]]>
                    </category>
                
                    <category>
                        <![CDATA[ APIs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Onyeanuna Prince ]]>
                </dc:creator>
                <pubDate>Mon, 04 Nov 2024 16:44:16 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730415311732/58afe01c-0ac4-4351-a4b4-a15729b5bcb1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you’re documenting an API reference, there are two main approaches you can follow. You can either use the manual approach of filling in the endpoints via a user interface, or organize a structured document containing all the necessary information about your API.</p>
<p>This structured document is called an <a target="_blank" href="https://www.openapis.org/">OpenAPI specification</a> (OpenAPI Spec or OAS).</p>
<p>An OpenAPI spec is a format for describing APIs. It's a blueprint that outlines everything about how an API works — what endpoints are available, what data you can send or receive, and what responses to expect.</p>
<p>This means that a well-written OAS file means well-written API reference documentation.</p>
<p>When writing this file, there are some parts that can get a bit complicated. For example, you might have to document a single endpoint with different methods or sometimes duplicate endpoints.</p>
<p>I encountered and documented both of those use cases. So, in this article, I'll show you how you can do the same. We'll go through each use case with sample OpenAPI specs, and at the end, I'll leave you with some useful tips for documenting your OpenAPI spec files.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-the-foundation">Setting the Foundation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-case-1-duplicate-endpoints">Use Case 1: Duplicate Endpoints</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-case-2-how-to-document-multiple-http-methods">Use Case 2: How to Document Multiple HTTP Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-api-documentation-tips">API Documentation Tips</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-use-markdown-in-openapi">Use Markdown in OpenAPI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-the-operationid-field">Use the operationId Field</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-ref-for-reusable-components">Use $ref for Reusable Components</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>There are a few things you need to know to follow along with the use cases below. These include:</p>
<ol>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/how-apis-work/"><strong>A basic knowledge of APIs and API documentation</strong></a>: Familiarity with API terminology and structure (for example, endpoints, methods, request/response structure) is essential to understand how an OpenAPI Specification (OAS) document functions.</p>
</li>
<li><p><a target="_blank" href="https://spec.openapis.org/oas/latest.html"><strong>Familiarity with OpenAPI Specification</strong></a>: Basic understanding of OAS, including its purpose, structure, and so on.</p>
</li>
<li><p><strong>Access to Swagger or other OpenAPI documentation tools</strong>: You need tools like the <a target="_blank" href="https://editor-next.swagger.io/">Swagger Editor</a> or <a target="_blank" href="https://rapidocweb.com/">RapiDoc</a>, which will allow you to test and view the OpenAPI files visually.</p>
</li>
</ol>
<h2 id="heading-setting-the-foundation"><strong>Setting the Foundation</strong></h2>
<p>In both programming and in life, if you can determine that something is "complex," this means that there's also a simplistic-regular way it can be as well. And that's the same for an OAS file.</p>
<p>When creating your spec file, you might not always encounter the use cases we'll address shortly. That's why it’s useful to know what a conventional spec file looks like.</p>
<p>An OpenAPI spec is a human and machine-readable file written in JSON or YAML. Below is an example of an OAS file structure in YAML format:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">paths:</span>
  <span class="hljs-string">/users:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Get</span> <span class="hljs-string">a</span> <span class="hljs-string">list</span> <span class="hljs-string">of</span> <span class="hljs-string">users</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">A</span> <span class="hljs-string">list</span> <span class="hljs-string">of</span> <span class="hljs-string">users.</span>
  <span class="hljs-string">/users/{userId}:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Get</span> <span class="hljs-string">details</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">single</span> <span class="hljs-string">user</span>
      <span class="hljs-attr">parameters:</span>
 <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">userId</span>
          <span class="hljs-attr">in:</span> <span class="hljs-string">path</span>
          <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
          <span class="hljs-attr">schema:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Details</span> <span class="hljs-string">of</span> <span class="hljs-string">a</span> <span class="hljs-string">single</span> <span class="hljs-string">user.</span>
  <span class="hljs-string">/orders:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Get</span> <span class="hljs-string">a</span> <span class="hljs-string">list</span> <span class="hljs-string">of</span> <span class="hljs-string">orders</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">A</span> <span class="hljs-string">list</span> <span class="hljs-string">of</span> <span class="hljs-string">orders.</span>
</code></pre>
<p>Here's a brief breakdown of this OAS file structure:</p>
<ol>
<li><p><strong>Paths</strong>: The <code>paths</code> section allows you to list each endpoint or URL that you can interact with in this API. Each path, such as <code>/users</code> or <code>/orders</code>, shows what type of data you can get or send to that URL.</p>
</li>
<li><p><strong>Operations</strong>: Under each path, there's a method or operation, like <code>GET</code>, which tells us what we can do with that endpoint. In this example, each path uses <code>GET</code>, which means you request information.</p>
</li>
<li><p><strong>Summary</strong>: Each operation has a <code>summary</code> — a short description explaining what the endpoint does, like "Get a list of users" or "Get details for a single user."</p>
</li>
<li><p><strong>Parameters</strong>: For paths that include placeholders, like <code>/users/{userId}</code>, you'll see a <code>parameters</code> section explaining what details are required.</p>
</li>
<li><p><strong>Responses</strong>: Each operation includes a <code>responses</code> section, which lists the possible API responses.</p>
</li>
</ol>
<p><strong>NOTE</strong>: This is not a complete OAS file. I omitted some preceding information for the purpose of this explanation.</p>
<p>Now, let’s dive into the more complex scenarios.</p>
<h2 id="heading-use-case-1-duplicate-endpoints"><strong>Use Case 1: Duplicate Endpoints</strong></h2>
<p>During the development of an API, you may create a single endpoint with multiple variations. Depending on the use case, you might want that endpoint to accept multiple data formats or specific parameters.</p>
<p>When you encounter such scenarios and want to document the API reference using an OpenAPI spec, you won't be able to replicate it exactly how it is in the <a target="_blank" href="https://postman.com/">Postman</a> collection (or any other development environment).</p>
<p>If you did try, you'll get this error:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730414590959/017c94c1-7e33-46c7-b572-b9ea03763e1f.png" alt="Failed OpenAPI Spec" width="600" height="400" loading="lazy"></p>
<p>The workaround for this problem is to consolidate these multiple variations under a single path definition by grouping the different requests and responses as <strong>examples</strong>.</p>
<p>In the example below, you have an API that has an endpoint for managing session registration at a conference. This endpoint has various requests and responses based on registration type (for example, Speaker, Attendee, or VIP).</p>
<p>In a Postman collection, you can have each of these endpoints in a separate folder for easy identification and testing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730414608239/be94b45d-fb16-438f-9e7e-07cdc38c179d.png" alt="Postman collection" width="600" height="400" loading="lazy"></p>
<p>But when documenting your spec file, it should look like this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">openapi:</span> <span class="hljs-number">3.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">info:</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">Conference</span> <span class="hljs-string">Events</span> <span class="hljs-string">API</span>
  <span class="hljs-attr">description:</span> <span class="hljs-string">API</span> <span class="hljs-string">to</span> <span class="hljs-string">manage</span> <span class="hljs-string">event</span> <span class="hljs-string">registrations</span> <span class="hljs-string">for</span> <span class="hljs-string">conferences</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/register-session:</span>
    <span class="hljs-attr">post:</span>
      <span class="hljs-attr">tags:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Registration</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Register</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">conference</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Register</span> <span class="hljs-string">a</span> <span class="hljs-string">user</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">specific</span> <span class="hljs-string">session</span> <span class="hljs-string">based</span> <span class="hljs-string">on</span> <span class="hljs-string">their</span> <span class="hljs-string">role,</span> <span class="hljs-string">with</span> <span class="hljs-string">details</span> <span class="hljs-string">provided</span> <span class="hljs-string">for</span> <span class="hljs-string">each</span> <span class="hljs-string">registration</span> <span class="hljs-string">type.</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">registerSession</span>
      <span class="hljs-attr">requestBody:</span>
        <span class="hljs-attr">description:</span> <span class="hljs-string">Registers</span> <span class="hljs-string">a</span> <span class="hljs-string">user</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">session</span> <span class="hljs-string">at</span> <span class="hljs-string">the</span> <span class="hljs-string">conference.</span> <span class="hljs-string">It</span> <span class="hljs-string">accepts</span> <span class="hljs-string">different</span> <span class="hljs-string">formats</span> <span class="hljs-string">for</span> <span class="hljs-string">attendance,</span> <span class="hljs-string">speaker,</span> <span class="hljs-string">or</span> <span class="hljs-string">VIP</span> <span class="hljs-string">registrations.</span>
        <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
        <span class="hljs-attr">content:</span>
          <span class="hljs-attr">application/json:</span>
            <span class="hljs-attr">schema:</span>
              <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/SessionRegistration'</span>
            <span class="hljs-attr">examples:</span>
              <span class="hljs-attr">Attendee:</span>
                <span class="hljs-attr">summary:</span> <span class="hljs-string">Register</span> <span class="hljs-string">as</span> <span class="hljs-string">an</span> <span class="hljs-string">Attendee</span>
                <span class="hljs-attr">value:</span>
                  <span class="hljs-attr">userType:</span> <span class="hljs-string">Attendee</span>
                  <span class="hljs-attr">userId:</span> <span class="hljs-number">789</span>
                  <span class="hljs-attr">sessionId:</span> <span class="hljs-number">1234</span>
                  <span class="hljs-attr">preferences:</span>
                    <span class="hljs-attr">seating:</span> <span class="hljs-string">General</span>
                    <span class="hljs-attr">accessLevel:</span> <span class="hljs-string">Basic</span>
              <span class="hljs-attr">Speaker:</span>
                <span class="hljs-attr">summary:</span> <span class="hljs-string">Register</span> <span class="hljs-string">as</span> <span class="hljs-string">a</span> <span class="hljs-string">Speaker</span>
                <span class="hljs-attr">value:</span>
                  <span class="hljs-attr">userType:</span> <span class="hljs-string">Speaker</span>
                  <span class="hljs-attr">userId:</span> <span class="hljs-number">456</span>
                  <span class="hljs-attr">sessionId:</span> <span class="hljs-number">1234</span>
                  <span class="hljs-attr">preferences:</span>
                    <span class="hljs-attr">seating:</span> <span class="hljs-string">VIP</span>
                    <span class="hljs-attr">accessLevel:</span> <span class="hljs-string">Full</span>
                    <span class="hljs-attr">presentationEquipment:</span> <span class="hljs-string">Projector</span>
              <span class="hljs-attr">VIP:</span>
                <span class="hljs-attr">summary:</span> <span class="hljs-string">Register</span> <span class="hljs-string">as</span> <span class="hljs-string">VIP</span>
                <span class="hljs-attr">value:</span>
                  <span class="hljs-attr">userType:</span> <span class="hljs-string">VIP</span>
                  <span class="hljs-attr">userId:</span> <span class="hljs-number">123</span>
                  <span class="hljs-attr">sessionId:</span> <span class="hljs-number">1234</span>
                  <span class="hljs-attr">preferences:</span>
                    <span class="hljs-attr">seating:</span> <span class="hljs-string">Front</span> <span class="hljs-string">Row</span>
                    <span class="hljs-attr">accessLevel:</span> <span class="hljs-string">Full</span>
                    <span class="hljs-attr">exclusiveAccess:</span> <span class="hljs-literal">true</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Successful</span> <span class="hljs-string">registration</span> <span class="hljs-string">for</span> <span class="hljs-string">Attendee,</span> <span class="hljs-string">Speaker,</span> <span class="hljs-string">or</span> <span class="hljs-string">VIP</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
                <span class="hljs-attr">properties:</span>
                  <span class="hljs-attr">registrationId:</span>
                    <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
                  <span class="hljs-attr">success:</span>
                    <span class="hljs-attr">type:</span> <span class="hljs-string">boolean</span>
              <span class="hljs-attr">examples:</span>
                <span class="hljs-attr">Attendee:</span>
                  <span class="hljs-attr">summary:</span> <span class="hljs-string">Response</span> <span class="hljs-string">for</span> <span class="hljs-string">Attendee</span> <span class="hljs-string">registration</span>
                  <span class="hljs-attr">value:</span>
                    <span class="hljs-attr">registrationId:</span> <span class="hljs-string">att-456def</span>
                    <span class="hljs-attr">success:</span> <span class="hljs-literal">true</span>
                <span class="hljs-attr">Speaker:</span>
                  <span class="hljs-attr">summary:</span> <span class="hljs-string">Response</span> <span class="hljs-string">for</span> <span class="hljs-string">Speaker</span> <span class="hljs-string">registration</span>
                  <span class="hljs-attr">value:</span>
                    <span class="hljs-attr">registrationId:</span> <span class="hljs-string">spk-123abc</span>
                    <span class="hljs-attr">success:</span> <span class="hljs-literal">true</span>
                <span class="hljs-attr">VIP:</span>
                  <span class="hljs-attr">summary:</span> <span class="hljs-string">Response</span> <span class="hljs-string">for</span> <span class="hljs-string">VIP</span> <span class="hljs-string">registration</span>
                  <span class="hljs-attr">value:</span>
                    <span class="hljs-attr">registrationId:</span> <span class="hljs-string">vip-789ghi</span>
                    <span class="hljs-attr">success:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">SessionRegistration:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">userType:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Type</span> <span class="hljs-string">of</span> <span class="hljs-string">user</span> <span class="hljs-string">registering</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">Attendee,</span> <span class="hljs-string">Speaker,</span> <span class="hljs-string">VIP)</span>
        <span class="hljs-attr">userId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Unique</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">user</span>
        <span class="hljs-attr">sessionId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Unique</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">session</span> <span class="hljs-string">to</span> <span class="hljs-string">register</span> <span class="hljs-string">for</span>
        <span class="hljs-attr">preferences:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
          <span class="hljs-attr">properties:</span>
            <span class="hljs-attr">seating:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Seating</span> <span class="hljs-string">preference</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">General,</span> <span class="hljs-string">VIP,</span> <span class="hljs-string">Front</span> <span class="hljs-string">Row)</span>
            <span class="hljs-attr">accessLevel:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Access</span> <span class="hljs-string">level</span> <span class="hljs-string">granted</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">Basic,</span> <span class="hljs-string">Full)</span>
            <span class="hljs-attr">presentationEquipment:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Required</span> <span class="hljs-string">equipment</span> <span class="hljs-string">for</span> <span class="hljs-string">Speakers</span> <span class="hljs-string">(only</span> <span class="hljs-string">applicable</span> <span class="hljs-string">to</span> <span class="hljs-string">Speaker)</span>
            <span class="hljs-attr">exclusiveAccess:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">boolean</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Exclusive</span> <span class="hljs-string">access</span> <span class="hljs-string">for</span> <span class="hljs-string">VIP</span> <span class="hljs-string">users</span>
</code></pre>
<p>In this file, you have a single <code>POST /register-session</code> path that captures all registration types without duplicating endpoints.</p>
<p>Here's a visual representation of this OAS file using the <a target="_blank" href="https://editor-next.swagger.io/">Swagger editor</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730414627353/eed5843b-f5f4-4e61-9126-51fd10e417c6.png" alt="OpenAPI Spec Multiple Request Examples" width="600" height="400" loading="lazy"></p>
<h2 id="heading-use-case-2-how-to-document-multiple-http-methods"><strong>Use Case 2: How to Document Multiple HTTP Methods</strong></h2>
<p>Another use case you may encounter happens when you have the same endpoint but different HTTP methods.</p>
<p>This usually comes up because each method serves a different purpose, even though they share the same path.</p>
<p>For example, a <strong>GET</strong> method retrieves information about a resource, like viewing a user's registration details for a conference session.</p>
<p>On the other hand, a <strong>PATCH</strong> method updates specific fields for that same user registration, like updating their seat preference.</p>
<p>Since both the <code>GET</code> and <code>PATCH</code> methods relate to the same resource (<code>/register-session</code> in our example), the way around this is to group them under the same path. This way, you'll be documenting two separate methods for a single path.</p>
<p>In OpenAPI, each combination of a path and method is called an "operation". Grouping operations that share the same path helps maintain clearer and more structured documents.</p>
<p>Using the conference events API example, this is what your OAS file should look like:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">openapi:</span> <span class="hljs-number">3.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">info:</span>
  <span class="hljs-attr">title:</span> <span class="hljs-string">Conference</span> <span class="hljs-string">Events</span> <span class="hljs-string">API</span>
  <span class="hljs-attr">description:</span> <span class="hljs-string">API</span> <span class="hljs-string">to</span> <span class="hljs-string">manage</span> <span class="hljs-string">event</span> <span class="hljs-string">registrations</span> <span class="hljs-string">for</span> <span class="hljs-string">conferences</span>
  <span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/register-session:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">tags:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Registration</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Retrieve</span> <span class="hljs-string">a</span> <span class="hljs-string">registration</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">conference</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Fetch</span> <span class="hljs-string">details</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">specific</span> <span class="hljs-string">user's</span> <span class="hljs-string">registration,</span> <span class="hljs-string">like</span> <span class="hljs-string">seat</span> <span class="hljs-string">assignment</span> <span class="hljs-string">and</span> <span class="hljs-string">access</span> <span class="hljs-string">level.</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">getSessionRegistration</span>
      <span class="hljs-attr">parameters:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-attr">in:</span> <span class="hljs-string">query</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">userId</span>
          <span class="hljs-attr">schema:</span>
            <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">The</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">user</span> <span class="hljs-string">whose</span> <span class="hljs-string">registration</span> <span class="hljs-string">you</span> <span class="hljs-string">want</span> <span class="hljs-string">to</span> <span class="hljs-string">retrieve.</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Registration</span> <span class="hljs-string">details</span> <span class="hljs-string">retrieved</span> <span class="hljs-string">successfully</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/SessionRegistration'</span>
              <span class="hljs-attr">example:</span>
                <span class="hljs-attr">userId:</span> <span class="hljs-number">789</span>
                <span class="hljs-attr">sessionId:</span> <span class="hljs-number">1234</span>
                <span class="hljs-attr">preferences:</span>
                  <span class="hljs-attr">seating:</span> <span class="hljs-string">General</span>
                  <span class="hljs-attr">accessLevel:</span> <span class="hljs-string">Basic</span>
                  <span class="hljs-attr">exclusiveAccess:</span> <span class="hljs-literal">false</span>

    <span class="hljs-attr">patch:</span>
      <span class="hljs-attr">tags:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">Registration</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Update</span> <span class="hljs-string">a</span> <span class="hljs-string">registration</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">conference</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Update</span> <span class="hljs-string">specific</span> <span class="hljs-string">fields</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">user's</span> <span class="hljs-string">session</span> <span class="hljs-string">registration,</span> <span class="hljs-string">such</span> <span class="hljs-string">as</span> <span class="hljs-string">seating</span> <span class="hljs-string">or</span> <span class="hljs-string">access</span> <span class="hljs-string">level.</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">updateSessionRegistration</span>
      <span class="hljs-attr">requestBody:</span>
        <span class="hljs-attr">description:</span> <span class="hljs-string">Allows</span> <span class="hljs-string">updating</span> <span class="hljs-string">fields</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">specific</span> <span class="hljs-string">session</span> <span class="hljs-string">registration.</span>
        <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
        <span class="hljs-attr">content:</span>
          <span class="hljs-attr">application/json:</span>
            <span class="hljs-attr">schema:</span>
              <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/UpdateSessionPreferences'</span>
            <span class="hljs-attr">example:</span>
              <span class="hljs-attr">userId:</span> <span class="hljs-number">789</span>
              <span class="hljs-attr">preferences:</span>
                <span class="hljs-attr">seating:</span> <span class="hljs-string">VIP</span>
                <span class="hljs-attr">accessLevel:</span> <span class="hljs-string">Full</span>
                <span class="hljs-attr">exclusiveAccess:</span> <span class="hljs-literal">true</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Registration</span> <span class="hljs-string">updated</span> <span class="hljs-string">successfully</span>
          <span class="hljs-attr">content:</span>
            <span class="hljs-attr">application/json:</span>
              <span class="hljs-attr">schema:</span>
                <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
                <span class="hljs-attr">properties:</span>
                  <span class="hljs-attr">success:</span>
                    <span class="hljs-attr">type:</span> <span class="hljs-string">boolean</span>
                  <span class="hljs-attr">message:</span>
                    <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">example:</span>
                <span class="hljs-attr">success:</span> <span class="hljs-literal">true</span>
                <span class="hljs-attr">message:</span> <span class="hljs-string">"Registration updated successfully."</span>
<span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">SessionRegistration:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">userId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Unique</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">user</span>
        <span class="hljs-attr">sessionId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Unique</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">session</span>
        <span class="hljs-attr">preferences:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
          <span class="hljs-attr">properties:</span>
            <span class="hljs-attr">seating:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Seating</span> <span class="hljs-string">preference</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">General,</span> <span class="hljs-string">VIP,</span> <span class="hljs-string">Front</span> <span class="hljs-string">Row)</span>
            <span class="hljs-attr">accessLevel:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Access</span> <span class="hljs-string">level</span> <span class="hljs-string">granted</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">Basic,</span> <span class="hljs-string">Full)</span>
            <span class="hljs-attr">exclusiveAccess:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">boolean</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Exclusive</span> <span class="hljs-string">access</span> <span class="hljs-string">granted</span> <span class="hljs-string">to</span> <span class="hljs-string">certain</span> <span class="hljs-string">users</span>

    <span class="hljs-attr">UpdateSessionPreferences:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">userId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Unique</span> <span class="hljs-string">ID</span> <span class="hljs-string">of</span> <span class="hljs-string">the</span> <span class="hljs-string">user</span>
        <span class="hljs-attr">preferences:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
          <span class="hljs-attr">properties:</span>
            <span class="hljs-attr">seating:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">New</span> <span class="hljs-string">seating</span> <span class="hljs-string">preference</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">VIP)</span>
            <span class="hljs-attr">accessLevel:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Updated</span> <span class="hljs-string">access</span> <span class="hljs-string">level</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-string">Full)</span>
            <span class="hljs-attr">exclusiveAccess:</span>
              <span class="hljs-attr">type:</span> <span class="hljs-string">boolean</span>
              <span class="hljs-attr">description:</span> <span class="hljs-string">Updated</span> <span class="hljs-string">access</span> <span class="hljs-string">preference</span> <span class="hljs-string">(e.g.,</span> <span class="hljs-literal">true</span> <span class="hljs-string">or</span> <span class="hljs-literal">false</span><span class="hljs-string">)</span>
</code></pre>
<p>In this file, you have a single <code>/register-session</code> path with multiple methods. We define just one path, <code>/register-session</code>, and list the <code>GET</code> and <code>PATCH</code> methods under it. This keeps the spec clean, reduces duplication, and shows that these methods relate to the same resource.</p>
<p>Here's a visual representation of this OAS file using the Swagger editor:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730414663261/680dd222-8d36-41be-a73a-10a55771d906.png" alt="Multiple methods in one operation in an OpenAPI spec" width="600" height="400" loading="lazy"></p>
<h2 id="heading-api-documentation-tips"><strong>API Documentation Tips</strong></h2>
<p>While working with OpenAPI specifications, there are some useful tricks and tips that can make your OAS file more readable and maintainable.</p>
<h3 id="heading-use-markdown-in-openapi"><strong>Use Markdown in OpenAPI</strong></h3>
<p>OpenAPI specifications allow the use of Markdown in the <code>description</code> field. The version of Markdown used in OAS is called CommonMark, the same version used in GitHub.</p>
<p>Markdown formatting allows you to make text more visually engaging and organized. You can add formatting such as headers, lists, code blocks, bold, italics, and so on, which can make your documentation easier to scan and more accessible for readers.</p>
<p>For example, if you need to emphasize certain parts of an endpoint's purpose or highlight important details, Markdown lets you do it naturally.</p>
<p>You can add Markdown directly into any <code>description</code> field in the OpenAPI file, like this:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">paths:</span>
  <span class="hljs-string">/register-session:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">|
        ## Retrieve Session Registration
</span>       <span class="hljs-string">Retrieves</span> <span class="hljs-string">the</span> <span class="hljs-string">registration</span> <span class="hljs-string">details</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">specific</span> <span class="hljs-string">user.</span>  
       <span class="hljs-bullet">-</span> <span class="hljs-string">**Note:**</span> <span class="hljs-string">This</span> <span class="hljs-string">data</span> <span class="hljs-string">includes</span> <span class="hljs-string">seat</span> <span class="hljs-string">assignment</span> <span class="hljs-string">and</span> <span class="hljs-string">access</span> <span class="hljs-string">level.</span>  
       <span class="hljs-bullet">-</span> <span class="hljs-attr">Example of JSON response:</span> <span class="hljs-string">`{"userId":</span> <span class="hljs-number">789</span><span class="hljs-string">,</span> <span class="hljs-attr">"sessionId":</span> <span class="hljs-number">1234</span><span class="hljs-string">,</span> <span class="hljs-attr">"seating":</span> <span class="hljs-string">"General"</span><span class="hljs-string">}`</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Registration</span> <span class="hljs-string">details</span> <span class="hljs-string">retrieved</span> <span class="hljs-string">successfully</span>
</code></pre>
<p>When deployed to supported documentation platforms like <a target="_blank" href="https://rapidocweb.com/">RapiDoc</a> or <a target="_blank" href="https://readme.com/">ReadMe</a>, this will render beautifully with all your Markdown styling intact.</p>
<p>Here's a deployed version of this example in Readme:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730414669217/100bcde8-a25e-4eab-9102-5113476a334b.png" alt="Markdown in description field on Readme" width="600" height="400" loading="lazy"></p>
<h3 id="heading-use-the-operationid-field"><strong>Use the</strong> <code>operationId</code> Field</h3>
<p>The <code>operationId</code> field is an optional field in OpenAPI specs that assigns a unique name to each API operation.</p>
<p>It is an identifier that you can use to call specific methods when integrating with SDKs or when linking between parts of your documentation.</p>
<p>By effectively using the <code>operationId</code>, you make it much easier for developers to reference specific actions in the API, which is especially helpful when the API is complex or has multiple endpoints.</p>
<p>Place the <code>operationId</code> inside each HTTP method block to give it a unique identifier. For instance:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">paths:</span>
  <span class="hljs-string">/register-session:</span>
    <span class="hljs-attr">get:</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">getSessionRegistration</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Retrieve</span> <span class="hljs-string">a</span> <span class="hljs-string">registration</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">conference</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Successfully</span> <span class="hljs-string">retrieved</span> <span class="hljs-string">the</span> <span class="hljs-string">registration</span>
    <span class="hljs-attr">patch:</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">updateSessionRegistration</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Update</span> <span class="hljs-string">a</span> <span class="hljs-string">registration</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">conference</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'200':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Registration</span> <span class="hljs-string">updated</span> <span class="hljs-string">successfully</span>
</code></pre>
<p>With the <code>operationId</code>, developers can directly refer to <code>getSessionRegistration</code> or <code>updateSessionRegistration</code> as function calls in code or API clients.</p>
<h3 id="heading-use-ref-for-reusable-components"><strong>Use</strong> <code>$ref</code> for Reusable Components</h3>
<p>The <code>$ref</code> keyword in OpenAPI lets you create and reuse components across your spec file. This technique is especially helpful when you have similar request bodies, responses, or parameters repeated in multiple endpoints.</p>
<p>By defining components in a single place and referencing them as needed, you avoid redundancy, reduce errors, and facilitate updates.</p>
<p>So, instead of updating the same parameter across multiple locations, you update it once in the reusable component, and every endpoint using it gets the update.</p>
<p>To use it, first define the reusable component in the components section of your OpenAPI file, then reference it elsewhere using <code>$ref</code>:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">components:</span>
  <span class="hljs-attr">schemas:</span>
    <span class="hljs-attr">RegistrationDetails:</span>
      <span class="hljs-attr">type:</span> <span class="hljs-string">object</span>
      <span class="hljs-attr">properties:</span>
        <span class="hljs-attr">userId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
        <span class="hljs-attr">sessionId:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">integer</span>
        <span class="hljs-attr">seating:</span>
          <span class="hljs-attr">type:</span> <span class="hljs-string">string</span>
<span class="hljs-attr">paths:</span>
  <span class="hljs-string">/register-session:</span>
    <span class="hljs-attr">post:</span>
      <span class="hljs-attr">summary:</span> <span class="hljs-string">Register</span> <span class="hljs-string">for</span> <span class="hljs-string">a</span> <span class="hljs-string">session</span>
      <span class="hljs-attr">requestBody:</span>
        <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
        <span class="hljs-attr">content:</span>
          <span class="hljs-attr">application/json:</span>
            <span class="hljs-attr">schema:</span>
              <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/RegistrationDetails'</span>
      <span class="hljs-attr">responses:</span>
        <span class="hljs-attr">'201':</span>
          <span class="hljs-attr">description:</span> <span class="hljs-string">Successfully</span> <span class="hljs-string">registered</span> <span class="hljs-string">for</span> <span class="hljs-string">the</span> <span class="hljs-string">session</span>
</code></pre>
<p>In this file, <code>RegistrationDetails</code> is defined once and is referenced using the <code>$ref</code> keyword in the <code>/register-session</code> operation.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>In this article, you learned how to resolve some complex use cases you might encounter when documenting your API reference using an OpenAPI specification. We went through what to do when you have a single endpoint with multiple methods or duplicate endpoints.</p>
<p>Creating your API reference without an OpenAPI spec file is a manual approach that can become redundant if you have to replicate it across various platforms. But by relying on the tips from the article, you're sure to create better, more efficient, and more reusable OpenAPI specifications. And these, in turn, will lead to better API documentation.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Automate Documentation Conversion with Pandoc in CI/CD Pipelines ]]>
                </title>
                <description>
                    <![CDATA[ In any software project, documentation plays a crucial role in guiding developers, users, and stakeholders through the project's features and functionalities. As projects grow and evolve, managing documentation across various formats—whether it’s mar... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines/</link>
                <guid isPermaLink="false">671949e0521b33716a071ccc</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ci-cd ]]>
                    </category>
                
                    <category>
                        <![CDATA[ automation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Preston Mayieka ]]>
                </dc:creator>
                <pubDate>Wed, 23 Oct 2024 19:09:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729707865753/d1703b32-ccb4-4cd1-9c3e-3e66fef7e02f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In any software project, documentation plays a crucial role in guiding developers, users, and stakeholders through the project's features and functionalities.</p>
<p>As projects grow and evolve, managing documentation across various formats—whether it’s markdown, HTML, or PDF for offline use—can become a time-consuming and error-prone task.</p>
<p><a target="_blank" href="https://pandoc.org/"><strong>Pandoc</strong></a> is a powerful tool that allows you to convert documentation between formats seamlessly.</p>
<p>Still, even with Pandoc, manually converting files for every update can become a bottleneck in large projects or teams where documentation is frequently updated.</p>
<p>In this article, I’ll guide you through setting up shell scripts, using Makefiles, and integrating Pandoc into CI/CD pipelines to streamline your workflow and keep your documentation up-to-date with minimal effort.</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#Why-Automate-Documentation-Conversion">Why Automate Documentation Conversion</a>?</p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-automate-pandoc-using-shell-scripts">How to Automate Pandoc using Shell Scripts</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#basic-shell-script-for-pandoc-conversion">Basic Shell Script for Pandoc Conversion</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#customizing-the-script-for-several-files">Customizing the Script for Several Files</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#automating-with-makefiles">Automating with Makefiles</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#a-makefile-for-pandoc-conversions">A Makefile for Pandoc Conversions</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#defining-dependencies-in-makefiles">Defining Dependencies in Makefiles</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#why-use-makefiles-for-pandoc-automation">Why Use Makefiles for Pandoc Automation?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-integrate-pandoc-with-ci-cd-pipelines">How to Integrate Pandoc with CI/CD Pipelines</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#example-setting-up-pandoc-with-github-actions">Example: Setting Up Pandoc with GitHub Actions</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#triggering-on-documentation-updates">Triggering on Documentation Updates</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#adapting-for-gitlab-ci-or-jenkins">Adapting for GitLab CI or Jenkins</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#advanced-automation-techniques">Advanced Automation Techniques</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#automating-with-cron-jobs">Automating with Cron Jobs</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#ensuring-consistency-with-docker">Ensuring Consistency with Docker</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#combining-tools-for-efficiency">Combining Tools for Efficiency</a></p>
</li>
<li><p><a target="_blank" href="https://freecodecamp.org/news/how-to-automate-documentation-conversion-with-pandoc-in-cicd-pipelines#conclusion">Conclusion</a></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729625689479/bfba6404-0a0c-4dab-9a15-0058b33c3c0c.png" alt="bfba6404-0a0c-4dab-9a15-0058b33c3c0c" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-why-automate-documentation-conversion">Why Automate Documentation Conversion?</h2>
<p>Manually converting documentation between formats in large projects can become a daunting task.</p>
<p>Whether you're generating <strong>HTML</strong>, <strong>PDF</strong>, or <strong>DOCX</strong> versions from the same source, repeating this process for every update leads to various challenges:</p>
<ul>
<li><p><strong>Time-Consuming</strong>: Running manual commands to convert documentation every time you make a change eats into valuable development time when updates happen often.</p>
</li>
<li><p><strong>Prone to Errors</strong>: The manual process increases the likelihood of mistakes, such as using incorrect commands, missing steps, or generating outdated versions of your documentation. These inconsistencies can confuse both developers and end-users.</p>
</li>
<li><p><strong>Difficult to Scale</strong>: As projects grow in size, managing documents across different formats without automation can become unmanageable. Teams working in parallel may struggle to keep documentation synchronized, leading to mismatches between formats.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729627548454/96b38163-5eda-4412-83fb-483180410c61.png" alt="96b38163-5eda-4412-83fb-483180410c61" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>By automating the conversion process with tools like Pandoc, you can overcome these challenges and enjoy a range of benefits:</p>
<ul>
<li><p><strong>Consistency</strong>: Automation ensures that all versions of your documentation are always up-to-date and accurate. No matter the number of formats you're generating, the process remains standardized.</p>
</li>
<li><p><strong>Efficiency</strong>: Automated workflows free up time by handling repetitive tasks in the background, allowing teams to focus on development rather than manually managing documentation updates.</p>
</li>
<li><p><strong>Scalability</strong>: With automation, it’s straightforward to scale documentation efforts as your project grows. Whether you're maintaining a single document or an entire library of resources, automation makes sure everything stays synchronized with minimal effort.</p>
</li>
</ul>
<p>The next section explores how to automate the conversion process.</p>
<h2 id="heading-how-to-automate-pandoc-using-shell-scripts">How to Automate Pandoc using Shell Scripts</h2>
<p>By using <a target="_blank" href="https://medium.com/@jadhav.swatissj99/introduction-to-shell-scripting-automate-your-workflow-efficiently-d9415537e990">shell scripts</a>, you can streamline the process of running <a target="_blank" href="https://pandoc.org/getting-started.html#step-6-converting-a-file">PanDoc commands</a>, saving time and reducing the risk of errors associated with manual command execution.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729627613042/5a2b2c62-3f67-42a5-81fe-5d4ff58714c3.png" alt="5a2b2c62-3f67-42a5-81fe-5d4ff58714c3" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-basic-shell-script-for-pandoc-conversion">Basic Shell Script for PanDoc Conversion</h3>
<p>To get started, we’ll create a shell script that converts a single Markdown file into various formats.</p>
<p>For instance, here’s a script that converts <code>input.md</code> into HTML and PDF:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Convert input.md to HTML and PDF</span>
pandoc input.md -o output.html
pandoc input.md -o output.pdf

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Conversion complete!"</span>
</code></pre>
<p>In the above script:</p>
<ul>
<li><p>The <code>#!/bin/bash</code> line indicates that the script should be run using the Bash shell.</p>
</li>
<li><p>The pandoc commands convert the <code>input.md</code> file into <code>output.html</code> and <code>output.pdf</code>.</p>
</li>
<li><p>The <code>echo</code> command confirms that the conversion process is complete.</p>
</li>
</ul>
<h3 id="heading-customizing-the-script-for-several-files">Customizing the Script for Several Files</h3>
<p>If you want to convert all Markdown files in a directory, you can customize your script to process several files at once.</p>
<p>For instance, here’s a script that converts <code>input.md</code> into <code>HTML</code> and <code>PDF</code>:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Go through all the Markdown files present in the current directory</span>
<span class="hljs-keyword">for</span> file <span class="hljs-keyword">in</span> *.md; <span class="hljs-keyword">do</span>
  <span class="hljs-comment"># Convert each Markdown file to PDF</span>
  pandoc <span class="hljs-string">"<span class="hljs-variable">$file</span>"</span> -o <span class="hljs-string">"<span class="hljs-variable">${file%.md}</span>.pdf"</span>
<span class="hljs-keyword">done</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"All conversions complete!"</span>
</code></pre>
<p>In this script:</p>
<ul>
<li><p>The <code>for</code> loop iterates over each <code>.md</code> file in the current directory.</p>
</li>
<li><p>The <code>pandoc</code> command converts each Markdown file to a PDF, preserving the original filename but changing the extension to <code>.pdf</code> with the <code>${file%.md}.pdf</code> syntax.</p>
</li>
<li><p>The final <code>echo</code> confirms that all conversions are complete.</p>
</li>
</ul>
<h3 id="heading-adding-error-handling-and-complex-logic">Adding Error Handling and Complex Logic</h3>
<p>To enhance your script's robustness, you can add error handling and extra logic.</p>
<p>For instance, perhaps you want to make sure that Pandoc is installed before proceeding, and handle cases where the input file may be missing.</p>
<p>The script will be as follows:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Check if Pandoc is installed</span>
<span class="hljs-keyword">if</span> ! <span class="hljs-built_in">command</span> -v pandoc &amp;&gt; /dev/null; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"Pandoc is not installed. Please install it and try again."</span>
  <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Go through all the Markdown files present in the current directory</span>
<span class="hljs-keyword">for</span> file <span class="hljs-keyword">in</span> *.md; <span class="hljs-keyword">do</span>
  <span class="hljs-keyword">if</span> [ -e <span class="hljs-string">"<span class="hljs-variable">$file</span>"</span> ]; <span class="hljs-keyword">then</span>
    <span class="hljs-comment"># Convert each Markdown file to PDF</span>
    pandoc <span class="hljs-string">"<span class="hljs-variable">$file</span>"</span> -o <span class="hljs-string">"<span class="hljs-variable">${file%.md}</span>.pdf"</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Converted <span class="hljs-variable">$file</span> to PDF."</span>
  <span class="hljs-keyword">else</span>
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"No Markdown files found."</span>
  <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">done</span>

<span class="hljs-built_in">echo</span> <span class="hljs-string">"All conversions complete!"</span>
</code></pre>
<p>In this enhanced script:</p>
<ul>
<li><p>The <code>if ! command -v pandoc &amp;&gt; /dev/null; then</code> line checks whether Pandoc is installed.</p>
</li>
<li><p>The <code>if [ -e "$file" ]; then</code> statement checks if each Markdown file exists before attempting to convert it.</p>
</li>
<li><p>An informative message is printed after each successful conversion, providing feedback on the process.</p>
</li>
</ul>
<p>As your project grows in complexity, relying solely on shell scripts for automation can become difficult to manage when dealing with lots of files and frequent updates.</p>
<p>This is where <strong>Makefiles</strong> come in handy.</p>
<h3 id="heading-automating-with-makefiles">Automating with Makefiles</h3>
<p>A <a target="_blank" href="https://opensource.com/article/18/8/what-how-makefile">Makefile</a> is a special file that defines rules and commands for automating tasks in a project.</p>
<p>It’s widely used by developers to <strong>compile code</strong>, but developers can also leverage it for non-compilation tasks, such as converting documentation formats with Pandoc.</p>
<h3 id="heading-a-makefile-for-pandoc-conversions">A Makefile for Pandoc Conversions</h3>
<p>Here’s an example of how you can create a Makefile to automate Pandoc conversions:</p>
<pre><code class="lang-makefile"><span class="hljs-section">all: html pdf</span>

<span class="hljs-section">html:</span>
    pandoc input.md -o output.html

<span class="hljs-section">pdf:</span>
    pandoc input.md -o output.pdf
</code></pre>
<p>In this Makefile:</p>
<ul>
<li><p><code>all</code> is the default target. When you run <code>make</code> without specifying a target, it will run the <code>html</code> and <code>pdf</code> targets sequentially.</p>
</li>
<li><p>The <code>html</code> target runs a PanDoc command to convert <a target="_blank" href="http://input.md"><code>input.md</code></a> into <code>output.html</code>.</p>
</li>
<li><p>The <code>pdf</code> target runs a PanDoc command to convert <a target="_blank" href="http://input.md"><code>input.md</code></a> into <code>output.pdf</code>.</p>
</li>
</ul>
<p>To use this Makefile, run the following command in your terminal:</p>
<pre><code class="lang-bash">codemake
</code></pre>
<p>This will execute both the <code>html</code> and <code>pdf</code> targets, converting the Markdown file into both formats.</p>
<h3 id="heading-defining-dependencies-in-makefiles">Defining Dependencies in Makefiles</h3>
<p>One of the major strengths of Makefiles is their ability to handle <strong>dependencies</strong>.</p>
<p>In the context of documentation conversion, you can specify which files to update when you <strong>detect changes</strong> in the source file.</p>
<p>Let’s look at an example:</p>
<pre><code class="lang-makefile"><span class="hljs-section">output.html: input.md</span>
    pandoc input.md -o output.html

<span class="hljs-section">output.pdf: input.md</span>
    pandoc input.md -o output.pdf
</code></pre>
<p>In this Makefile:</p>
<ul>
<li><p>The <code>output.html</code> and <code>output.pdf</code> files depend on <code>input.md</code>.</p>
</li>
<li><p>If you run make output.html or make output.pdf, Pandoc will regenerate the corresponding file if you update <code>input.md</code> after the last time you created the output file.</p>
</li>
</ul>
<p>This ensures that Pandoc converts the files that have changed, saving time when working on large documentation projects.</p>
<h3 id="heading-why-use-makefiles-for-pandoc-automation">Why Use Makefiles for Pandoc Automation?</h3>
<p>Makefiles offer several advantages for automating Pandoc conversions in larger projects:</p>
<ul>
<li><p><strong>Efficiency</strong>: Makefiles rebuild what’s necessary, meaning you won’t waste time converting files that haven’t changed.</p>
</li>
<li><p><strong>Simplicity</strong>: Once set up, running <code>make</code> simplifies the conversion process to a single command, making it easier for teams to maintain consistent documentation workflows.</p>
</li>
<li><p><strong>Scalability</strong>: As your project grows, you can add more targets and dependencies to the Makefile, automating everything from documentation to more complex build processes.</p>
</li>
</ul>
<p>Makefiles are an excellent option for automating documentation conversions, when combined with Pandoc for multi-format outputs.</p>
<p>They help ensure that your workflow is <strong>efficient</strong> and your documentation remains up-to-date.</p>
<p>As modern development practices increasingly rely on <a target="_blank" href="https://www.redhat.com/en/topics/devops/what-is-ci-cd#:~:text=CI%2FCD%2C%20which%20stands%20for,a%20shared%20source%20code%20repository.">Continuous Integration and Continuous Deployment (CI/CD)</a>, automating routine tasks such as documentation generation becomes essential.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729626428543/8194dc35-8a1a-4d91-b4b0-8b8ce7174eba.jpeg" alt="8194dc35-8a1a-4d91-b4b0-8b8ce7174eba" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Integrating Pandoc into your <a target="_blank" href="https://www.redhat.com/en/topics/devops/what-cicd-pipeline">CI/CD pipelines</a> allows for seamless documentation conversion and updates, ensuring that your docs are always up-to-date without manual intervention.</p>
<p>By automating this process, you can focus on coding and building, while your pipeline handles the conversion and distribution of your project documentation. Let’s explore how to set up Pandoc in a CI/CD pipeline to streamline your documentation workflows.</p>
<h2 id="heading-how-to-integrate-pandoc-with-cicd-pipelines">How to Integrate Pandoc with CI/CD Pipelines</h2>
<p>Automating documentation generation within your CI/CD pipeline brings significant benefits, including consistency, efficiency, and hands-off updates.</p>
<p>Whether you’re using <a target="_blank" href="https://github.com/features/actions">GitHub Actions</a>, <a target="_blank" href="https://about.gitlab.com/topics/ci-cd/">GitLab CI</a>, <a target="_blank" href="https://www.jenkins.io/">Jenkins</a>, or another automation tool, integrating Pandoc ensures that documentation gets generated and distributed whenever changes occur.</p>
<p>This approach reduces the risk of <strong>outdated</strong> or <strong>inconsistent</strong> documentation.</p>
<h3 id="heading-example-setting-up-pandoc-with-github-actions">Example: Setting Up Pandoc with GitHub Actions</h3>
<p>Let’s walk through a clear example of how you can use <strong>GitHub Actions</strong> to automate the process of generating documentation with Pandoc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729626613665/ddc1ddd8-2049-4971-8883-1f86bd80a558.png" alt="ddc1ddd8-2049-4971-8883-1f86bd80a558" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Below is a basic workflow that converts a <strong>Markdown file (*.md)</strong> into a <strong>PDF</strong> whenever code gets pushed to the repository.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Generate</span> <span class="hljs-string">Documentation</span>

<span class="hljs-attr">on:</span> [<span class="hljs-string">push</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
      <span class="hljs-comment"># Step 1: Checkout code from the repository</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">code</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

      <span class="hljs-comment"># Step 2: Install Pandoc</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Pandoc</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">sudo</span> <span class="hljs-string">apt-get</span> <span class="hljs-string">install</span> <span class="hljs-string">pandoc</span>

      <span class="hljs-comment"># Step 3: Convert Markdown to PDF</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Convert</span> <span class="hljs-string">Markdown</span> <span class="hljs-string">to</span> <span class="hljs-string">PDF</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">pandoc</span> <span class="hljs-string">input.md</span> <span class="hljs-string">-o</span> <span class="hljs-string">output.pdf</span>

      <span class="hljs-comment"># Step 4: Upload the generated PDF as an artifact</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">Documentation</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/upload-artifact@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">name:</span> <span class="hljs-string">documentation</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">output.pdf</span>
</code></pre>
<p>Here’s a breakdown of each step:</p>
<ul>
<li><p><strong>Checkout Code</strong>: The <code>actions/checkout@v2</code> action retrieves the latest code from your repository.</p>
</li>
<li><p><strong>Install Pandoc</strong>: This step installs Pandoc on the runner (in this case, an Ubuntu machine) so that it can gets used for the documentation conversion.</p>
</li>
<li><p><strong>Convert Markdown to PDF</strong>: The PanDoc command converts the <a target="_blank" href="http://input.md"><code>input.md</code></a> file into <code>output.pdf</code>.</p>
</li>
<li><p><strong>Upload Documentation</strong>: This step saves the generated PDF as an artifact in the CI/CD pipeline, making it downloadable or accessible later</p>
</li>
</ul>
<h3 id="heading-triggering-on-documentation-updates">Triggering on Documentation Updates</h3>
<p>You can configure your CI/CD pipeline to trigger when documentation updates occur, for example, when changes get pushed to a <code>docs</code> branch:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">docs</span>
</code></pre>
<p>This setup ensures that your documentation gets regenerated when changes are specifically made to the documentation branch, reducing unnecessary rebuilds.</p>
<h3 id="heading-adapting-for-gitlab-ci-or-jenkins">Adapting for GitLab CI or Jenkins</h3>
<p>While the above example uses GitHub Actions, the same principles work on other CI/CD systems like <strong>GitLab CI</strong> or <strong>Jenkins</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729626674435/91e102a9-cb70-4819-bb0d-5a60f16dcdae.jpeg" alt="91e102a9-cb70-4819-bb0d-5a60f16dcdae" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>For instance, in GitLab CI, you could define a <code>.gitlab-ci.yml</code> file that follows similar steps to check out the code, install Pandoc, convert the files, and store the resulting documentation.</p>
<p>Integrating Pandoc into your CI/CD pipeline offers a reliable way to automate your documentation workflows, ensuring that your project docs are always current, accurate, and accessible.</p>
<h2 id="heading-advanced-automation-techniques">Advanced Automation Techniques</h2>
<p>When your project reaches a stage where documentation needs to be generated frequently or across multiple environments, it’s essential to extend your automation strategy to maintain consistency and reliability.</p>
<h3 id="heading-automating-with-cron-jobs">Automating with Cron Jobs</h3>
<p>For projects where documentation updates occur frequently, but not always due to code pushes or commits, you can automate the process using <a target="_blank" href="https://en.wikipedia.org/wiki/Cron"><strong>cron jobs</strong></a>.</p>
<p>Cron allows you to <strong>schedule tasks</strong> at specific intervals, meaning your documentation can automatically get updated at set times without needing manual input.</p>
<p>For example, setting up a cron job to run every day at midnight to convert Markdown files to PDFs:</p>
<pre><code class="lang-bash">0 0 * * * /path/to/pandoc /path/to/input.md -o /path/to/output.pdf
</code></pre>
<p>With this cron job in place, Pandoc will automatically convert your Markdown files to PDFs at the specified time, ensuring that your documentation remains up-to-date without manual intervention.</p>
<h3 id="heading-ensuring-consistency-with-docker">Ensuring Consistency with Docker</h3>
<p>When working in a team or across various systems, ensuring that Pandoc runs consistently in different environments can be challenging.</p>
<p><a target="_blank" href="https://www.docker.com/">Docker</a> provides a solution to this by allowing you to package Pandoc and all its dependencies in a container, ensuring that the same setup gets used everywhere.</p>
<p>This is useful in CI/CD pipelines, where different environments (like local machines, staging, and production servers) can have different configurations.</p>
<p>You can use the official <a target="_blank" href="https://hub.docker.com/u/pandoc"><strong>Pandoc Docker image</strong></a> to simplify the setup process:</p>
<pre><code class="lang-bash">docker run --rm -v $(<span class="hljs-built_in">pwd</span>):/data pandoc/core:latest input.md -o output.pdf
</code></pre>
<p>This command runs Pandoc inside a Docker container, using the latest version of Pandoc, and mounts your current directory to the container’s <code>/data</code> directory.</p>
<p>By doing this, you ensure that no matter where the pipeline runs, the conversion will work the same way every time.</p>
<h3 id="heading-combining-tools-for-efficiency">Combining Tools for Efficiency</h3>
<p>By combining tools like <strong>cron jobs</strong> and <strong>Docker</strong>, you can set up an advanced automation pipeline that ensures:</p>
<ul>
<li><p><strong>Scheduled updates</strong>: Cron jobs trigger documentation generation at regular intervals.</p>
</li>
<li><p><strong>Consistency across environments</strong>: Docker ensures that Pandoc and its dependencies are the same on every machine.</p>
</li>
<li><p><strong>Reliability</strong>: Together, these tools help ensure that your documentation is always accurate, no matter where or when it’s generated.</p>
</li>
</ul>
<p>These advanced techniques allow you to further streamline your documentation workflows, improving both efficiency and reliability as your project grows.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>Automating documentation conversion with Pandoc not only saves time but also ensures consistency and scalability as your project grows.</p>
<p>Whether you’re managing small or large projects, these techniques enable you to focus on coding and building, knowing that your documentation is automatically up-to-date and ready for distribution.</p>
<p>By embracing automation, you streamline your development process and enhance collaboration across teams, ensuring that your documentation evolves as efficiently as your code.</p>
<p>Now it’s time to apply these tools to your projects and enjoy the benefits of a fully automated documentation pipeline.</p>
<p><strong>Let’s stay in touch:</strong></p>
<ul>
<li><p><a target="_blank" href="https://www.linkedin.com/in/preston-mayieka/">Connect with me on LinkedIn</a>. I post regularly, so following me is a great idea.</p>
</li>
<li><p><a target="_blank" href="https://mobile.x.com/Preston_Mayieka">Follow me on X</a></p>
</li>
</ul>
<p>Feel free to reach out through the channels above if you have any questions. I will be happy to help.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Documentation Site using React and Docusaraus ]]>
                </title>
                <description>
                    <![CDATA[ Having a properly designed and comprehensive documentation site is important for any project. But creating good documentation can be challenging, and problems like poor user onboarding experience and increased support tickets can become daily hassles... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-documentation-site-using-react-and-docusaraus/</link>
                <guid isPermaLink="false">6706b5ae1446e5644b75b252</guid>
                
                    <category>
                        <![CDATA[ docusaurus ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Technical writing  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chisom Uma ]]>
                </dc:creator>
                <pubDate>Wed, 09 Oct 2024 16:56:14 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728407506914/49f6f7cd-af92-405e-ac89-d71bd74e3f18.avif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Having a properly designed and comprehensive documentation site is important for any project. But creating good documentation can be challenging, and problems like poor user onboarding experience and increased support tickets can become daily hassles for a team.</p>
<p>This is why documentation tools like Docusaurus are great for helping you create visually stunning documentation sites in abo 5 minutes.</p>
<p>In this tutorial, I'll show you how to build a documentation site using React and Docusaurus.</p>
<p>If you are new to Docusaurus, you are probably wondering, “why React?, why not any other framework like Next.js?”, Don’t worry – I’ll also answer this question in this guide.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-docusaurus">What is Docusaurus?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started-and-installation">Getting Started and Installation</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-project-structure">Project structure</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-start-your-docusaurus-website">How to Start Your Docusaurus Website</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-create-documentation-overview">How to Create Documentation (Overview)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-mdx-and-react-components">MDX and React Components</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-tabs">Tabs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-alerts-or-admonitions">Alerts or Admonitions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-code-blocks">Code blocks</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-docusaurus-blog">Docusaurus Blog</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-custom-pages">Custom Pages</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-styling-in-docusaurus">Styling in Docusaurus</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-deployment">Deployment</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along with this guide, you should have:</p>
<ul>
<li><p><strong>Node.js</strong> version 18.0 or above installed</p>
</li>
<li><p>Basic knowledge of React and Markdown</p>
</li>
<li><p>IDE (preferably VSCode)</p>
</li>
</ul>
<h2 id="heading-what-is-docusaurus">What is Docusaurus?</h2>
<p><a target="_blank" href="https://docusaurus.io/">Docusaurus</a> was released by the Meta Open Source team in 2017 to help devs build, deploy, and maintain documentation websites easily and quickly. The project’s other goal was to improve the speed of both developers and end users using the <a target="_blank" href="https://web.dev/articles/apply-instant-loading-with-prpl">PRPL</a> pattern.</p>
<p>Some of its cool features include search and localization, powered by <a target="_blank" href="https://www.algolia.com/">Algolia</a> (search) and <a target="_blank" href="https://crowdin.com/">Crowdin</a> (language support and internationalization).</p>
<p>Now, let’s talk about why we’re using React for this tutorial. Well, Docusaurus is built on top of React, which makes it easy to customize the website. Also, Docusaurus supports Markdown and MDX (which lets you use React JSX in your markdown content).</p>
<p>As a technical writer myself, I love that this tool supports Markdown, which I'm quite familiar with. It allows me to focus on creating helpful documentation without worrying about converting the text to other text formats.</p>
<h2 id="heading-getting-started-and-installation">Getting Started and Installation</h2>
<p>Getting started with Docusaraus is pretty straightforward. The first thing you need to do is head over to your terminal and run the command below:</p>
<pre><code class="lang-plaintext">npx create-docusaurus@latest my-website classic
</code></pre>
<p><strong>Note:</strong> The Docusaurus team recommends the <code>classic</code> template because it is easier to get started with fast. It also contains <code>@docusaurus/preset-classic</code> – which includes standard documentation, a blog, custom pages, and a CSS framework (with dark mode support).</p>
<h3 id="heading-project-structure">Project structure</h3>
<p>After installation, this is what your newly created Docusaurus project structure should look like:</p>
<pre><code class="lang-plaintext">📦my-website
┣ 📂blog
┃ ┣ 📂2021-08-26-welcome
┃ ┃ ┣ 📜docusaurus-plushie-banner.jpeg
┃ ┃ ┗ 📜index.md
┃ ┣ 📜2019-05-28-first-blog-post.md
┃ ┣ 📜2019-05-29-long-blog-post.md
┃ ┣ 📜2021-08-01-mdx-blog-post.mdx
┃ ┣ 📜authors.yml
┃ ┗ 📜tags.yml
┣ 📂docs
┃ ┣ 📂tutorial-basics
┃ ┃ ┣ 📜congratulations.md
┃ ┃ ┣ 📜create-a-blog-post.md
┃ ┃ ┣ 📜create-a-document.md
┃ ┃ ┣ 📜create-a-page.md
┃ ┃ ┣ 📜deploy-your-site.md
┃ ┃ ┣ 📜markdown-features.mdx
┃ ┃ ┗ 📜_category_.json
┃ ┣ 📂tutorial-extras
┃ ┃ ┣ 📂img
┃ ┃ ┃ ┣ 📜docsVersionDropdown.png
┃ ┃ ┃ ┗ 📜localeDropdown.png
┃ ┃ ┣ 📜manage-docs-versions.md
┃ ┃ ┣ 📜translate-your-site.md
┃ ┃ ┗ 📜_category_.json
┃ ┗ 📜intro.md
┣ 📂src
┃ ┣ 📂components
┃ ┃ ┗ 📂HomepageFeatures
┃ ┃ ┃ ┣ 📜index.js
┃ ┃ ┃ ┗ 📜styles.module.css
┃ ┣ 📂css
┃ ┃ ┗ 📜custom.css
┃ ┗ 📂pages
┃ ┃ ┣ 📜index.js
┃ ┃ ┣ 📜index.module.css
┃ ┃ ┗ 📜markdown-page.md
┣ 📂static
┃ ┣ 📂img
┃ ┃ ┣ 📜docusaurus-social-card.jpg
┃ ┃ ┣ 📜docusaurus.png
┃ ┃ ┣ 📜favicon.ico
┃ ┃ ┣ 📜logo.svg
┃ ┃ ┣ 📜undraw_docusaurus_mountain.svg
┃ ┃ ┣ 📜undraw_docusaurus_react.svg
┃ ┃ ┗ 📜undraw_docusaurus_tree.svg
┃ ┗ 📜.nojekyll
┣ 📜.gitignore
┣ 📜babel.config.js
┣ 📜docusaurus.config.js
┣ 📜package.json
┣ 📜README.md
┗ 📜sidebars.js
</code></pre>
<p>Now, let’s explore some of the main directories:</p>
<ul>
<li><p><code>blog/</code>: This is where you store your blog posts</p>
</li>
<li><p><code>docs/</code>: As the name implies, this is where your documentation projects are kept</p>
</li>
<li><p><code>src/</code>: This directory allows you to customize your website further using React code.</p>
</li>
<li><p><code>static</code>: Here, you store static files like images, logos, favicons, and so on.</p>
</li>
</ul>
<p>A very important file is the <code>docusaurus.config.js</code> file, which acts as the main configuration file for your website.</p>
<h2 id="heading-how-to-start-your-docusaurus-website">How to Start Your Docusaurus Website</h2>
<p>To run your website locally, first open a new terminal on your IDE and run the following command below to start the development server:</p>
<pre><code class="lang-plaintext">cd my-website

npm i

npx docusaurus start
</code></pre>
<p>After running the above command, the browser compiles the React and Markdown files and starts a local development server at <a target="_blank" href="http://localhost:3000/">http://localhost:3000/</a>. Docusaurus enables hot reload, so you can see changes made to your React, Markdown, and MDX files automatically – without reloading your entire app.</p>
<p>Here is what the site looks like on your browser:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728389930307/b0bd7810-dea2-458b-85a1-e10b9a7b3028.png" alt="Bootstrapped Docusaurus site" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In the image above, you are first welcomed to an intuitive and easily navigable website. At the top left corner of the website, you will see the “<strong>Tutorial</strong>” and “<strong>Blog</strong>” sections.</p>
<ul>
<li><p><strong>Tutorial:</strong> This is where users can see the live version of your documentation.</p>
</li>
<li><p><strong>Blog:</strong> This is where users can see the live version of your blog.</p>
</li>
</ul>
<p>The link to the Docusaurus Open Source GitHub repo and the icon for toggling your website between light and dark modes are at the top-right corner of the site.</p>
<p>Alternatively, you can use <a target="_blank" href="https://docusaurus.io/docs/playground">docusaurus.new</a> to test Docusaurus quickly in a playground without having to go through the installation process. Here, you have an option to choose between <a target="_blank" href="https://codesandbox.io/">CodeSandbox</a> and <a target="_blank" href="https://stackblitz.com/">StackBlitz</a>.</p>
<h2 id="heading-how-to-create-documentation-overview">How to Create Documentation (Overview)</h2>
<p>Let’s take a closer look at our <code>docs</code> folder. If we head back to our local site and click on “<strong>Tutorial</strong>,” we will see some pre-built doc pages, as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728390116953/ec281a01-5b0c-413a-83b9-36d0352f3e03.png" alt="Documentation overview on the site" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>These documentation pages are reflected in the <code>docs</code> folder located in your IDE. When we open the <code>category.json</code> page, we can adjust the name or position of each page. This means you don’t have to name the folders the same as the page name, since the name of the file will be the URL of the page.</p>
<p>To create our new documentation, let’s use the following steps:</p>
<ol>
<li><p>Delete all the files in the docs folder. Your browser and terminal will typically display an error after this.</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728390294195/5a59bdc4-7a79-4b17-9e85-630867c6c3ec.png" alt="Error from deleted files" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p> This is because we need at least one page in the docs folder.</p>
</li>
<li><p>Create a new file inside the docs folder, which can be named anything you prefer, but in our case, I named it <a target="_blank" href="http://single-page.md">single-page.md</a>. You should see this change immediately reflected when you go to your local website. This is what you will see in the documentation pages section:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728390512797/90b86f29-8b03-414b-acff-18842cd4c462.png" alt="Single page " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
</li>
</ol>
<p>Inside this newly created file, you can create your documentation seamlessly. The image above shows the little Markdown content I created saying “Single Page” in an H1 and “This is a single page” in plain text.</p>
<p>Let’s say you want to create a more organized content structure, but you don’t know how to get started. Here are a few simple steps on how to do that:</p>
<ol>
<li><p>Create a new folder inside the <code>docs</code> folder, named “Getting Started”</p>
</li>
<li><p>Create new Markdown files inside the “Getting started” folder, and name them whatever you like. For the sake of this tutorial, let’s name it <a target="_blank" href="http://API-docs.md"><code>API-docs.md</code></a> and <a target="_blank" href="http://Session-replay.md"><code>Session-replay.md</code></a>.</p>
</li>
<li><p>Write your documentation in Markdown</p>
</li>
</ol>
<p>This is how the file structure should look like on your IDE:</p>
<pre><code class="lang-plaintext">📦docs
┣ 📂Getting started
┃ ┣ 📜Open-replay.md
┃ ┗ 📜Session-replay.md
┗ 📜single-page.md
</code></pre>
<p>Here is a simple GIF to demonstrate how this works on the local documentation website.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728390784981/9eed8cbf-c6dc-4508-9d75-401d87673cf7.gif" alt="GIF showing local documentation site" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Now, let’s try to create a separate page in the <code>doc</code> folder. To do this, let’s create a  <code>category.json</code> page in the <code>Getting started</code> folder. Inside the  <code>category.json</code>  file, we will include the following JSON text:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Custom Title"</span>,
  <span class="hljs-attr">"position"</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">"link"</span>: {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"generated-index"</span>,
    <span class="hljs-attr">"description"</span>: <span class="hljs-string">"This is a custom description"</span>
  }
}
</code></pre>
<ul>
<li><p>The <code>link</code> object creates a separate page for the folder.</p>
</li>
<li><p>The <code>type</code> property is set to generated-index, which means it will generate the pages with all the sub-pages.</p>
</li>
<li><p>The <code>description</code> property is a description of the page that will show up beneath the title.</p>
</li>
</ul>
<p>When you check out your local hosted documentation site, you will see that the label has changed, and a separate page has been created for the folder.</p>
<p>In this section, I will show you an example of how headings and tables of content work in Docusaurus.</p>
<p>The first thing I did was create a <a target="_blank" href="http://markdown.md"><code>markdown.md</code></a> file. Then I pasted a couple of headings in Markdown text format right inside the file, like this:</p>
<pre><code class="lang-markdown">---
title: Basic Markdown
<span class="hljs-section">sidebar<span class="hljs-emphasis">_position: 1
---

# Heading 1

## Heading 2

### Heading 3

#### Heading 4

##### Heading 5

###### Heading 6</span></span>
</code></pre>
<p>When we head back to our website, we can see that only headings level 2 and 3 are automatically added, just as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728391234366/1ba2a824-3d31-4fd2-bd3e-8fcb9547e073.png" alt="Image showing headers" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>We can edit to ensure that all the headings show up. To do this, first create a <a target="_blank" href="http://table-of-contents.md"><code>table-of-contents.md</code></a>, then paste in the following Markdown:</p>
<pre><code class="lang-markdown">---
title: Table of Contents
sidebar<span class="hljs-emphasis">_position: 2
toc_</span>min<span class="hljs-emphasis">_heading_</span>level: 2
<span class="hljs-section">toc<span class="hljs-emphasis">_max_</span>heading<span class="hljs-emphasis">_level: 6
---

import TOCInline from '@theme/TOCInline';

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TOCInline</span> <span class="hljs-attr">toc</span>=<span class="hljs-string">{toc}</span> <span class="hljs-attr">minHeadingLevel</span>=<span class="hljs-string">{2}</span> <span class="hljs-attr">maxHeadingLevel</span>=<span class="hljs-string">{6}</span> /&gt;</span></span>

## Heading 2

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

### Heading 3

Some content here.

#### Heading 4

Some content here.

##### Heading 5

Some content here.

###### Heading 6

Some content here.

## Heading 2

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

### Heading 3

Some content here.

#### Heading 4

Some content here.

##### Heading 5

Some content here.

###### Heading 6

Some content here.

## Heading 2

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

### Heading 3

Some content here.

#### Heading 4

Some content here.

##### Heading 5

Some content here.

###### Heading 6

Some content here.</span></span>
</code></pre>
<p>I added a TOC property and set the minimum and maximum heading levels with <code>toc_min_heading_level: 2</code> and <code>toc_max_heading_level: 6</code>. We also added an inline table of contents by first importing <code>TOCInline</code> from <code>@theme/TOCInline</code>. Then, we created a TOCInline component (which can be put anywhere you want your TOC to show up).</p>
<p>Now, all the headings show up in the table of contents part of the website:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728398728652/37595594-3dbc-42bc-853c-f5b5ba9714c4.png" alt="Image showing table of content and headers" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Beautiful right?</p>
<h2 id="heading-mdx-and-react-components">MDX and React Components</h2>
<p>Now, let’s talk about one of the most exciting features of Docusaurus: MDX and React components.</p>
<p>You might ask – how can Docusaurus use <code>TOC</code> or <code>import</code> in the Markdown file? Well, that’s because Docusaurus uses MDX, which is basically Markdown with JSX.</p>
<p>To demonstrate this, let’s create a new Markdown file inside our <code>Getting started</code> folder titled  <a target="_blank" href="http://MDX.md"><code>MDX.md</code></a> , then we create a separate file inside the <code>src</code> &gt; <code>components</code> folder and name the file <code>Tag.js</code> . Then we paste in the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Tag</span>(<span class="hljs-params">{ children, color }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span>
      <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
        <span class="hljs-attr">backgroundColor:</span> <span class="hljs-attr">color</span>,
        <span class="hljs-attr">borderRadius:</span> '<span class="hljs-attr">4px</span>',
        <span class="hljs-attr">color:</span> '#<span class="hljs-attr">fff</span>',
        <span class="hljs-attr">padding:</span> '<span class="hljs-attr">0.2rem</span> <span class="hljs-attr">0.5rem</span>',
        <span class="hljs-attr">fontWeight:</span> '<span class="hljs-attr">bold</span>',
      }}
    &gt;</span>
      {children}
    <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
  );
}
</code></pre>
<p>Here, we first imported the core React library, and then we defined a functional component called Tag, which takes in two props as input: <code>children</code> and <code>color</code>. In our return statement, we included our CSS styles for the <code>span</code> element.</p>
<p>Inside the <a target="_blank" href="http://MDX.md">MDX.md</a> file, paste in the below code:</p>
<pre><code class="lang-markdown">---
title: MDX
<span class="hljs-section">sidebar<span class="hljs-emphasis">_position: 3
---

import Tag from '@site/src/components/Tag';

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Tag</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#FF5733"</span>&gt;</span></span>Important<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">Tag</span>&gt;</span></span> information: This is an <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Tag</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"#3399FF"</span>&gt;</span></span>Exciting<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">Tag</span>&gt;</span></span> example of custom components!

I can write <span class="hljs-strong">**Markdown**</span> alongside my _</span>JSX<span class="hljs-emphasis">_!</span></span>
</code></pre>
<p>Here, we import <code>Tag</code> from our components folder. This is what it looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728398996580/a826b80c-1862-46f4-b111-dc6366dd13db.png" alt="Image showing how MDX works" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Note:</strong> Because we use MDX, Docusaurus comes with pre-built components like Tabs, alerts, code blocks, and more. Let’s check them out in the following subsections.</p>
<h3 id="heading-tabs">Tabs</h3>
<p>In this subsection, we’ll talk about tabs as a pre-built component in Docusaurus. Let’s dive right in!</p>
<p>For a start, let’s create a new Markdown file called <a target="_blank" href="http://tabs.md"><code>tabs.md</code></a> and paste in the following code:</p>
<pre><code class="lang-markdown">---
title: Tabs in Markdown
<span class="hljs-section">sidebar<span class="hljs-emphasis">_position: 4
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Tabs</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TabItem</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"book"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Book"</span> <span class="hljs-attr">default</span>&gt;</span></span>
    Dive into the world of knowledge with a captivating book 📚
  <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">TabItem</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TabItem</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"painting"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Painting"</span>&gt;</span></span>
    Admire the strokes of artistry on a beautiful painting 🖼️
  <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">TabItem</span>&gt;</span></span>
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">TabItem</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"music"</span> <span class="hljs-attr">label</span>=<span class="hljs-string">"Music"</span>&gt;</span></span>
    Let the soothing melodies of music transport you 🎶
  <span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">TabItem</span>&gt;</span></span>
<span class="xml"><span class="hljs-tag">&lt;/<span class="hljs-name">Tabs</span>&gt;</span></span>

I'm a text that doesn't belong to any tab. So I'm always visible.</span></span>
</code></pre>
<p>We imported <code>Tabs</code> from <code>@theme/Tabs</code> and <code>TabItem</code> from <code>@theme/TabItem</code>. Then, we created a Tabs component, which is the container, and the <code>TabItem</code> component is the tab itself. The <code>value</code> property is the value of the tab, while the <code>label</code> property is the label of the tab. The default property defines which tab is open by default – in this case, the “Book” tab.</p>
<p>This is how it looks:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728399214390/edece46f-3357-4b96-8672-a462a8a8916b.png" alt="Image showing how tabs work" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Each tab is clickable and transitions smoothly.</p>
<h3 id="heading-alerts-or-admonitions">Alerts or Admonitions</h3>
<p>Docusaurus comes with pre-built alerts or admonitions. To create an alert, you simply wrap the text with three colons and follow it with the type of alert you want the reader to have in mind.</p>
<p>Let’s create a new Markdown file called <a target="_blank" href="http://alerts.md">alerts.md</a> and paste in the following Markdown:</p>
<pre><code class="lang-markdown">---
title: Alerts or Admonitions
<span class="hljs-section">sidebar<span class="hljs-emphasis">_position: 5
---

:::note

Here's some <span class="hljs-strong">**information**</span> with _</span>Markdown<span class="hljs-emphasis">_ styling.

:::

:::tip

Here's a <span class="hljs-strong">**helpful tip**</span> with _</span>formatted text<span class="hljs-emphasis">_.

:::

:::info

Here's some <span class="hljs-strong">**useful info**</span> presented in a clear way.

:::

:::caution

Please take <span class="hljs-strong">**extra caution**</span> with this important note.

:::

:::danger

This is a <span class="hljs-strong">**dangerous situation**</span> you need to be aware of.

:::

:::note This is a _</span>custom title<span class="hljs-emphasis">_

And you can add images as well.

![<span class="hljs-string">alt text</span>](<span class="hljs-link">https://picsum.photos/600/400</span>)

:::</span></span>
</code></pre>
<p>The various types of alerts, as shown in the Markdown above, are:</p>
<ul>
<li><p><code>note</code></p>
</li>
<li><p><code>tip</code></p>
</li>
<li><p><code>info</code></p>
</li>
<li><p><code>caution</code></p>
</li>
<li><p><code>danger</code></p>
</li>
</ul>
<p>Here’s what it looks like on the website:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728402667575/cc10af2d-e417-4426-985b-4aad81a082db.png" alt="Image showing how alerts and admonitions work" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Alerts and admonitions are pretty common in documentation sites. So, if you have ever wondered how it’s been done, well, this is it! It’s quite straightforward.</p>
<h3 id="heading-code-blocks">Code blocks</h3>
<p>As we already know by now, Docusaurus supports MDX, which allows us to include code blocks in our files. Code blocks are text blocks wrapped around by strings of three backticks. You can add the name of the language after the last of the three backticks.</p>
<p>Let’s create a <a target="_blank" href="http://codeblocks.md"><code>codeblocks.md</code></a> file and paste the following JSX code:</p>
<pre><code class="lang-javascript">---
title: Codeblocks
<span class="hljs-attr">sidebar_position</span>: <span class="hljs-number">6</span>
---

<span class="hljs-string">``</span><span class="hljs-string">`jsx title="Codeblock"
function Greeting(props) {
  return &lt;p&gt;Welcome, {props.userName}!&lt;/p&gt;;
}

export default Greeting;
`</span><span class="hljs-string">``</span>

<span class="hljs-string">``</span><span class="hljs-string">`jsx title="Highlight Lines"
function HighlightText(highlight) {
  if (highlight) {
    // highlight-next-line
    return 'This text is highlighted!';
  }
  return 'Nothing highlighted';
}

function HighlightMoreText(highlight) {
  // highlight-start
  if (highlight) {
    return 'This range is highlighted!';
  }
  // highlight-end
  return 'Nothing highlighted';
}
`</span><span class="hljs-string">``</span>

<span class="hljs-string">``</span><span class="hljs-string">`jsx title="Line Numbers" showLineNumbers
import React from 'react';

function UserProfile(props) {
  const { username, email, isAdmin } = props;

  return (
    &lt;div&gt;
      &lt;h1&gt;User Profile&lt;/h1&gt;
      &lt;p&gt;Username: {username}&lt;/p&gt;
      &lt;p&gt;Email: {email}&lt;/p&gt;
      {isAdmin &amp;&amp; &lt;p&gt;Admin User&lt;/p&gt;}
    &lt;/div&gt;
  );
}

export default UserProfile;
`</span><span class="hljs-string">``</span>

<span class="hljs-string">``</span><span class="hljs-string">`jsx title="Line Numbers with Highlight" {4,9-11} showLineNumbers
import React from 'react';

function UserProfile(props) {
  const { username, email, isAdmin } = props;

  return (
    &lt;div&gt;
      &lt;h1&gt;User Profile&lt;/h1&gt;
      &lt;p&gt;Username: {username}&lt;/p&gt;
      &lt;p&gt;Email: {email}&lt;/p&gt;
      {isAdmin &amp;&amp; &lt;p&gt;Admin User&lt;/p&gt;}
    &lt;/div&gt;
  );
}

export default UserProfile;</span>
</code></pre>
<p>This is what the code blocks look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728402852316/4873fccd-d4b7-45d7-8d4f-49fea5a3da49.png" alt="Image showing how codeblocks work" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can easily copy the code by hovering your cursor over the code blocks and clicking on the copy icon on the top-right side of the code block.</p>
<p><strong>Note:</strong> By default, Docusaurus uses <code>Prism</code> for syntax highlighting.</p>
<p>If you also want to highlight some lines of code, you can do that by adding a comment like this:</p>
<pre><code class="lang-javascript">    <span class="hljs-comment">// highlight-next-line</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This text is highlighted!'</span>;
  }
  <span class="hljs-keyword">return</span> <span class="hljs-string">'Nothing highlighted'</span>;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">HighlightMoreText</span>(<span class="hljs-params">highlight</span>) </span>{
  <span class="hljs-comment">// highlight-start</span>
  <span class="hljs-keyword">if</span> (highlight) {
    <span class="hljs-keyword">return</span> <span class="hljs-string">'This range is highlighted!'</span>;
  }
  <span class="hljs-comment">// highlight-end</span>
</code></pre>
<ul>
<li><p><code>highlight-next-line</code>: allows you to highlight a single line of code</p>
</li>
<li><p><code>highlight-start and highlight-end</code>: allows you to highlight a range of lines</p>
</li>
</ul>
<h2 id="heading-docusaurus-blog">Docusaurus Blog</h2>
<p>The Docusaurus blog also comes by default with the <code>classic</code> template. If you don’t have a blog, you can add the following lines to your <code>docusaurus.config.js</code> file:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">label</span>: <span class="hljs-string">'Blog'</span>,
  <span class="hljs-attr">to</span>: <span class="hljs-string">'/blog'</span>,
}
</code></pre>
<p>Usually, this line should already be in your config file after installing Docusaurus for the first time.</p>
<p>The Docusaurus blog is very simple to understand. Navigate to the blog folder in the project explorer, and you’ll see all the blog posts, which are MDX files. The blog post date should be included on the file name as shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728403567052/c60d665d-f29b-433e-bd10-b86542d0063e.png" alt="Image showing blog folder" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>When you open one of the blog posts, you see something like this:</p>
<pre><code class="lang-markdown">---
slug: long-blog-post
title: Long Blog Post
authors: yangshun
<span class="hljs-section">tags: [hello, docusaurus]
---</span>

This is the summary of a very long blog post,

Use a <span class="hljs-code">`&lt;!--`</span> <span class="hljs-code">`truncate`</span> <span class="hljs-code">`--&gt;`</span> comment to limit blog post size in the list view.

<span class="xml"><span class="hljs-comment">&lt;!-- truncate --&gt;</span></span>

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
</code></pre>
<ul>
<li><p><code>slug</code>: You can add a slug to the URL of the blog post</p>
</li>
<li><p><code>title</code>: Title of the blog post</p>
</li>
<li><p><code>authors</code>: The authors of the blog post</p>
</li>
<li><p><code>tags</code>: Tags related to the blog post</p>
</li>
</ul>
<p>In the blog post, we can also use all the Markdown features plus JSX as we have seen before.</p>
<h2 id="heading-custom-pages">Custom Pages</h2>
<p>Technically, Docusaurus isn’t just a fancy documentation site generator with a blog. It’s a standard static site generator – which means you can create any page you want.</p>
<p>To see how creating a custom page in Docusaurus works, let’s create an about.js file in the <code>src</code> <strong>&gt;</strong> <code>pages</code> folder and include the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">'@theme/Layout'</span>;
<span class="hljs-keyword">import</span> Head <span class="hljs-keyword">from</span> <span class="hljs-string">'@docusaurus/Head'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">About</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"description"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"This is the about page"</span> /&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Head</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"red-text"</span>&gt;</span>About<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>This is the about page.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
  );
}
</code></pre>
<p>When you go to <a target="_blank" href="http://localhost:3000/about">http://localhost:3000/about</a>, you should see something like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728404291897/394ee43b-2b30-43f8-a8cf-ff260d51e82a.png" alt="Image showing how custom pages work " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>We can also add the page to the navbar by going to the docusaurus.config.js file and adding a new item to the navbar array. The item looks like this:</p>
<pre><code class="lang-json">{to: 'about', label: 'About', position: 'left'},
</code></pre>
<p>It then appears on the homepage nav menu like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728404457186/25545cf0-a5bf-4561-8dc8-49045c3cfc9d.png" alt="Image showing how custom pages work " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can now style and customize the <code>about.js</code> file any way you’d prefer using React.</p>
<h2 id="heading-styling-in-docusaurus">Styling in Docusaurus</h2>
<p>Let’s look at how you can style your site in Docusaurus. The easiest way is to customize the <code>custom.css</code> file inside the <code>css</code> <strong>&gt;</strong> <code>custom.css</code> file. This is what the file looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728404914713/bd2c8b65-52f9-43d4-b0c8-d09ec9562865.png" alt="Image showing how to perform styling" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here, you can change the whole color schema of the site and different styling to this file.</p>
<p>You can <strong>read more</strong> about this in the <a target="_blank" href="https://docusaurus.io/docs/styling-layout">Docusaurus styling and layout</a> docs.</p>
<h2 id="heading-seo-in-docusaurus">SEO in Docusaurus</h2>
<p>Docusaurus takes SEO very seriously. By default, Docusaurus automatically adds a description title, canonical URL links, and other useful metadata to each page. This can be configured as shown below:</p>
<pre><code class="lang-markdown">---
title: Our First Page
sidebar<span class="hljs-emphasis">_position: 1

description: A short description of this page
image: ../static/img/docusaurus-social-card.jpg
keywords: [keywords, describing, the main topics]
---

# Single Page

This is a single page.</span>
</code></pre>
<p>You can <strong>read more</strong> about this in the <a target="_blank" href="https://docusaurus.io/docs/seo">Docusaurus SEO</a> docs.</p>
<h2 id="heading-deployment">Deployment</h2>
<p>Deployment is pretty easy with Docusaurus. Since it’s a static site, you can deploy it to any static site hosting service. To do this, run the <code>npm run build</code> command on your CLI. This creates a build folder like the one below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1728405905725/a7633e46-cb10-4220-bce8-7b12545a124f.png" alt="Image showing build folder for deployment" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Then, you can upload the contents of the build folder to your hosting service.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we covered how to build documentation from scratch, how to create, customize, and style pages, and the awesome SEO power of Docusaurus.</p>
<p>Docusaurus is friendly to both developers and technical writers. As a developer, you can focus on customizing the site, while as a technical writer, you can focus on writing the documentation.</p>
<p>I will highly recommend this tool for both startups and established enterprises looking to build stunning documentation sites.</p>
<p>This guide is not exhaustive, but covers everything you need to know about the basics of building a documentation site with React and Docusaurus.</p>
<p>I hope you found it helpful :)</p>
<p>Here’s the link to my <a target="_blank" href="https://github.com/ChisomUma/docusaurus-project">GitHub code</a> for follow-up purposes.</p>
<p>And here’s the main Docusaurus <a target="_blank" href="https://docusaurus.io/docs/docs-introduction">documentation</a> if you’d like to dive in deeper.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write QA Documentation That Will Actually Work ]]>
                </title>
                <description>
                    <![CDATA[ Imagine developing a complex software product without taking any action to protect against errors. Human error and unexpected code combinations can cause a wide range of defects. This is where quality assurance (QA) documentation comes in.  Usually, ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-qa-documentation-that-will-actually-work/</link>
                <guid isPermaLink="false">66be14ba0c9c630f4d48debb</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Quality Assurance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oleh Romanyuk ]]>
                </dc:creator>
                <pubDate>Mon, 17 Jun 2024 18:29:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/How-to-Write-QA-Documentation-That-Will-Actually-Work.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Imagine developing a complex software product without taking any action to protect against errors. Human error and unexpected code combinations can cause a wide range of defects. This is where quality assurance (QA) documentation comes in. </p>
<p>Usually, a QA tester creates a report after discovering a bug. The next step is that they send a report to the bug handler. Basically, a bug handler is a developer that fixes a bug according to the detailed report. The bug handler ensures a clean and efficient QA process and makes it easier to have a clean conversation between the fixers and the testers. </p>
<p>But you might be wondering – why do we need QA documentation?</p>
<p>QA testing is essential in IT products today. Tight deadlines, unique skill sets within the organization, and the demand to develop products stress the need for a structured methodology. QA documentation guides testers through levels of clarity and overall coverage. </p>
<p>I've written this article to make your life a bit easier. So here it is, your ultimate guide on how to write software QA documentation that will work.</p>
<h3 id="heading-this-is-what-well-cover">This is what we'll cover:</h3>
<ul>
<li><a class="post-section-overview" href="#heading-make-a-test-plan-and-a-test-progress-report">Make a Test Plan and a Test Progress Report</a></li>
<li><a class="post-section-overview" href="#heading-create-test-cases">Create Test Cases</a></li>
<li><a class="post-section-overview" href="#heading-defect-reports">Defect Reports</a></li>
<li><a class="post-section-overview" href="#heading-useful-tips-for-defect-report-writing">Useful Tips for Defect Report Writing</a></li>
<li><a class="post-section-overview" href="#heading-submit-a-defect-report">Submit a Defect Report</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ul>
<h2 id="heading-make-a-test-plan-and-a-test-progress-report">Make a Test Plan and a Test Progress Report</h2>
<p>Developing great software requires a thorough and documented approach to testing. Everything begins in the development phase with a complete checkout plan as a template for the entire QA process. It outlines the general requirements, defines the followed route, identifies the necessary assets, and sets a simple timeline for achieving the objectives.</p>
<h3 id="heading-draw-up-a-roadmap-before-you-start">Draw up a roadmap before you start</h3>
<p>Before you start implementing your test plan, take some time to think about the big picture. Ask yourself:</p>
<p><em>What problem does this software solve?</em> As soon as you understand the main purpose of the software, you'll be able to manage the checkout process and identify the features that are most important to your goals. </p>
<p>I promise that once you see that you can do this, you quickly prioritize your efforts. They are based primarily on the importance of the functionality and its impact on the user.</p>
<h3 id="heading-create-a-plan">Create a plan</h3>
<p>The test plan is the central part of the QA technique. The test plan should contain the following key elements:</p>
<ul>
<li><strong>Imaginary test</strong>: Clearly identify the expected impact of the payment method. Will it confirm that core functionality is running smoothly, or will it alert you to capability gaps?</li>
<li><strong>Test method</strong>: Outline how the test will be performed. Will you do targeted testing, useless testing, or a mix of the two?</li>
<li><strong>Resource allocation</strong>: Identify the equipment and technology required to perform a complete control. What control framework will you use? Are specific hardware or software configurations required for proper control?</li>
<li><strong>Timetable and remaining dates</strong>: Establish a realistic timetable for the trial. Set clear deadlines to keep the project on track.</li>
</ul>
<h3 id="heading-understand-the-why-and-how">Understand the 'why' and 'how'</h3>
<p>A well-developed roadmap will ensure that key issues are addressed throughout the improvement approach:</p>
<ul>
<li><strong>Acceptance requirements</strong>: Clear fail/success criteria should be defined for all control cases. So, criteria allow the customer to understand that the product is high quality and ready for the end-user.</li>
<li><strong>Resource management</strong>: Identify the assets required for the testing. This includes preferred machines, copies of software in various forms, required expertise, and more.</li>
<li><strong>Team dynamics</strong>: Ensure that simple roles and tasks are defined within the test team. Who is responsible for particular test cases? Who documents bugs and who talks to developers?</li>
<li><strong>Time management</strong>: I advise setting realistic checkout times, taking into account project deadlines and the availability of useful help.</li>
</ul>
<p>The test progress report is another part of the QA documentation, similar to the test plan, but with additional data on current progress. This document allows you and your development team to monitor project progress and identify any organizational issues.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/test-plan-and-progress-report-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>A test plan and a progress report</em></p>
<h2 id="heading-create-test-cases">Create Test Cases</h2>
<p>Think of each test case as a detailed recipe for finding potential defects in the functionality of a software program. By following these "recipes" and evaluating the expected and actual results, defects can be accurately identified and addressed before preventive action is taken. </p>
<p>Each test case acts as an independent unit, outlining the steps required to evaluate a particular element of a software program. </p>
<p>Below is a breakdown of the key elements that make up a well-defined test case Here is my step-by-step guide for creating test cases:</p>
<ul>
<li><strong>ID</strong>: This is an identifier field to help distinguish between test cases and track them easily.</li>
<li><strong>Priority</strong>: This indicates the severity of the test case based on the functionality of the program and its impact on the normal overall performance of the known software program application.</li>
<li><strong>Test Requirements</strong>: These are requirements for testing software successfully, this can include reference documents also.</li>
<li><strong>Software Module</strong>: This shows the feature under testing. It also refers to the software requirements specifications (SRS) document explaining the software feature in detail.</li>
<li><strong>Test Context</strong>: This details the test plan to clarify how the daily tests will be carried out. It also identifies the test data required for a successful case study and includes unique and important statistical information.</li>
<li><strong>Expected Output</strong>: This describes the expected output to be displayed if the test is successful.</li>
<li><strong>Actual output</strong>: This indicates the actual result in the event of failure and shows the developer the errors in the application module of the software program.</li>
<li><strong>Comment</strong>: This is an optional section where the tester can give a description of the observations or add additional records.</li>
</ul>
<p>All QAs typically include the above elements, but can also be designed specifically for the task selected by the QA group. Also, each control case follows a lifecycle that defines the phases of creation, testing (pass, fail), completion, and so on. </p>
<p>In the next section, we’ll check out another important element of QA documentation: the defect report.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/test-cases.png" alt="Image" width="600" height="400" loading="lazy">
<em>Test cases</em></p>
<h2 id="heading-defect-reports">Defect Reports</h2>
<p>Defect reporting is an important element of QA documentation. Issue tracking is the detailed reporting of sudden problems that arise in a software product. Careful documentation of these issues lays the groundwork for a complex and bug-free final product. </p>
<p>Sounds simple, right? Yes, but only until you start documenting.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/bug-task.png" alt="Image" width="600" height="400" loading="lazy">
<em>A defect report</em></p>
<p>The bug report consists of the following sections: Identifier, Summary, Description, Steps to Reproduce, Reproducibility, Severity, Priority, Environment, and Attachments.</p>
<ul>
<li><strong>Identifier</strong>: Each software program problem is assigned a completely unique identifier that acts like a customized nameplate. This makes the QA documentation less complicated to navigate and allows verbal communication between the installer, tester, and project manager (PM).</li>
<li><strong>Summary:</strong> This is an opportunity to provide brief and informative answers to three basic questions: What was the problem? Where did the problem appear? Under what specific conditions did the problem appear?</li>
<li><strong>Explanation:</strong> Examine the failure log in more detail. Summarize the identified action (the result completed) and check it against the planned action (the predicted end result). Including a link to the app requirements of the software program can serve as a useful reference element.</li>
<li><strong>Reproduction method</strong> (STR): This phase should be considered as a step-by-step recipe for reproducing the defect. It should be strict and cover all the steps that caused the problem. Skipping critical steps can make it difficult for you to reproduce the problem and cause delays.</li>
<li><strong>Reproducibility:</strong> In this section, you clarify if the bug appears every time you follow the STR. You should use numbers to show approximate chances, for example, 7 times out of 10.</li>
<li><strong>Severity</strong>: Here you explain how much harm the bug may bring to the project. Essentially, this is a measure of the severity of the technical disruption that a bug will cause to the whole project. Remember that problems that are known to be minor can grow and cause you extreme problems throughout the software.</li>
<li><strong>Priority</strong>: Each error log assigns a problem priority that indicates its urgency. Common priorities are letters (A: highest priority, Z: highest priority), numbers (1: highest priority, 9: highest priority), or descriptive terms (high, medium, low).</li>
<li><strong>Environment</strong>: Specify the gadget or browser model in which the bug appeared. This will help you to put the problem in context and narrow down a valid cause.</li>
<li><strong>Attachments</strong>: If possible, enrich the documentation with screenshots, screen recordings, console log documents, and others. This will help to provide visual documentation of the error.</li>
</ul>
<p>My structure provides detailed information, so you can empower developers to effectively diagnose, address, and eliminate any software bugs. In this way, leading to more user-friendly and robust products. </p>
<p>Now, in the next section, we'll see some useful tips you can use for defect report writing.</p>
<h3 id="heading-useful-tips-for-defect-report-writing">Useful Tips for Defect Report Writing</h3>
<ol>
<li>Write a sufficient summary. It does not matter if it is long or short. What matters is that it should be clear.</li>
<li>Have a look at the summary and the description. Do they look pretty much the same? You must have forgotten to outline the expected and actual results in the description and to add the link to the requirements.</li>
<li>Capture the issue with the help of a screenshot. It may save you and the development team a lot of time. Sometimes one glance at the picture is just enough to understand the situation.</li>
<li>Before reporting the issue, try to reproduce it at least 3 times to be sure that it exists.</li>
<li>Report the issue ASAP and notify your project manager or product owner if the issue is major.</li>
<li>Check for grammar mistakes in your QA documentation so you're not taken down by the grammar police.</li>
<li>However comical it sounds, make sure that the issue is not a feature – review the documentation again!</li>
<li>Do not miss any important information in your Steps to Reproduce.</li>
</ol>
<h2 id="heading-submit-a-defect-report">Submit a Defect Report</h2>
<p>The final and one of the most important elements of QA documentation is the defect report. You may understand it covers the entire lifecycle of a problem, from its initial discovery to its final closure. </p>
<p>Let's now examine the key areas of this process:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/defect-report-lifecycle.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>a defect report lifecycle</em></p>
<p>We'll go over the defect report lifestyle piece by piece:</p>
<h3 id="heading-problem-reporting">Problem Reporting:</h3>
<p>This adventure begins with the careful compilation and submission of a report on the entire program. This serves as a roadmap for developers and provides a clear assessment of the problem.</p>
<h3 id="heading-triage-and-tasks">Triage and tasks:</h3>
<p>The task manager or technical lead takes on the role of gatekeeper at this stage. They carefully compare the files. If the file contains enough elements to work with, it is assigned to the developer and repaired. However, if the file is missing essential elements, it may be rejected for further improvement.</p>
<h3 id="heading-bug-fixing">Bug fixing:</h3>
<p>The assigned developer takes the initiative and works diligently to eliminate the annoying bug.</p>
<h3 id="heading-verification-and-completion">Verification and completion:</h3>
<p>Once the developer claims to have fixed the problem, it's your turn as QA. Carefully verify the fix by retesting the functionality in question. If everything works as it should, you are done. </p>
<p>The documentation has come to a happy end. Ideally, this will happen within a reasonable period of one to two weeks.</p>
<h3 id="heading-reboot-and-keep-going">Reboot and keep going:</h3>
<p>But it is not always that simple. If it is known that bugs are still being made in the validation system, there is no need to despair! </p>
<p>Re-open the bug documentation and send it to the developers for further attention. Sometimes the process of fixing bugs is repetitive and requires patience. But by being careful and effective, you can guarantee that all bug reports will eventually reach their final destination, resulting in a more polished and reliable software application product.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Quality Assurance is a process you simply cannot avoid. Each airplane prior to departure undergoes a technical check. If there is any issue, the aircraft is grounded until the problem is solved. The same goes for any software. </p>
<p>But QA documentation is not always "write and ignore". At some point in the software development lifecycle, QA documentation needs to be continually updated and improved as requirements change, new features are introduced, and feedback is received from deployment and production use.</p>
<p>There are also a growing number of styles that use synthetic intelligence and machine learning to partially automate the creation of QA documentation. </p>
<p>For example, natural language processing (NLP) is used to analyze requirements documents and generate draft control examples. Test bots can use NLP to interpret and routinely execute directed test cases. Predictive evaluation can also be used to identify the most dangerous areas of a software program that require more detailed control.</p>
<p>While these strategies are still new and not mature enough to replace human testers, they can help with growth and augment manual exploration, especially for large and complex builds. By making QA documentation a collaborative and ongoing hobby, your team can deliver better software faster and with fewer defects.</p>
<h3 id="heading-do-you-need-to-improve-the-quality-of-your-software">Do you need to improve the quality of your software?</h3>
<p>My company KeenEthics provides solid <a target="_blank" href="https://coventit.com/services/custom-software-development">development and quality assurance services</a>. In case you need an estimate for a similar project, feel free to <a target="_blank" href="https://coventit.com/contact-us">get in touch</a><em>.</em> </p>
<p>If you have enjoyed the article, you should continue with <a target="_blank" href="https://coventit.com/blog/How-IT-Outsourcing-Saves-Costs">How IT Outsourcing Saves Costs for Your Company</a> and <a target="_blank" href="https://coventit.com/blog/risks-of-it-outsourcing">Avoiding Pitfalls in IT Outsourcing: Tips for Minimizing Risks</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is a GitHub Wiki and How Do You Use it? ]]>
                </title>
                <description>
                    <![CDATA[ A GitHub wiki is a great place for your project's documentation. You can use the wiki to create, manage, and host documentation for your repository so others can use and contribute to your project. GitHub wikis are easy to start using without install... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-github-wiki-and-how-do-you-use-it/</link>
                <guid isPermaLink="false">66d038c3ccf811d3117aef0c</guid>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Rajdeep Singh ]]>
                </dc:creator>
                <pubDate>Mon, 15 Apr 2024 20:46:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/What-is-GitHub-Wiki-and-How-Do-You-Use-it.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A GitHub wiki is a great place for your project's documentation. You can use the wiki to create, manage, and host documentation for your repository so others can use and contribute to your project.</p>
<p>GitHub wikis are easy to start using without installing any other software. The best part is that the wiki is integrated with your GitHub repository. </p>
<p>You do not need any other tool – you just need to know how to use markdown, as you'll use it to write your wiki. (You can <a target="_blank" href="https://www.freecodecamp.org/news/github-flavored-markdown-syntax-examples/">read all about that in my other article here</a>.)</p>
<h2 id="heading-how-to-start-using-github-wiki">How to Start Using GitHub Wiki</h2>
<p>You can start your GitHub wiki with just one click. Every GitHub repository has a Wiki tab in the menu at the top of the page. To start, click on it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/github-wiki.png" alt="GitHub repository Page" width="600" height="400" loading="lazy">
<em>GitHub repository Page</em></p>
<p>The wiki tab is sometimes not shown by default in the GitHub repository nav bar. First, you'll need to enable wikis in your repository settings.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/no-wiki.png" alt="No wiki tab is show." width="600" height="400" loading="lazy">
<em>No wiki tab is shown.</em></p>
<p>To do that, go to your repository settings page, scroll down, and find the features section. Then enable wikis by checking the "Wikis" box.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Wiki-enable.png" alt="Enable wiki.in GitHub" width="600" height="400" loading="lazy">
<em>Enable wiki</em></p>
<p>To initialize the wiki in your GitHub repository, create the home page in your wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/first-page.png" alt="Initialize the wiki in GitHub." width="600" height="400" loading="lazy">
<em>Initialize the wiki in GitHub.</em></p>
<p>When you click the "<strong>Create the first page</strong>" button, you'll be redirected to the editor page where you can create a home page in the wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Home-wiki-Page.png" alt="Create a home page and initialize the wiki." width="600" height="400" loading="lazy">
<em>Create a home page and initialize the wiki.</em></p>
<p>Your wiki home page should now look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Your-wiki-is-look-like-this.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wiki home page</em></p>
<h2 id="heading-how-to-clone-a-github-wiki-locally">How to Clone a GitHub Wiki Locally</h2>
<p>Sometimes, new developers are confused about how to clone the wiki locally. To do this, just copy the link where it says “Clone this wiki locally”, as you can see in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/clone.png" alt="Copy the link to clone the GitHub wiki." width="600" height="400" loading="lazy">
<em>Copy the link to clone the GitHub wiki.</em></p>
<p>Copy that link and clone the GitHub wiki repository locally on your laptop or machine.</p>
<p>Now, you can make changes in the wiki, such as editing, updating, or changing documentation locally. After you finish any documentation changes, you can push your local wiki documentation to the GitHub wiki repository.</p>
<pre><code class="lang-bash">$ git <span class="hljs-built_in">clone</span> https://github.com/officialrajdeepsingh/github-wiki-tutorial.wiki.git
Cloning into <span class="hljs-string">'github-wiki-tutorial.wiki'</span>...
remote: Enumerating objects: 6, <span class="hljs-keyword">done</span>.
remote: Counting objects: 100% (6/6), <span class="hljs-keyword">done</span>.
remote: Compressing objects: 100% (2/2), <span class="hljs-keyword">done</span>.
remote: Total 6 (delta 1), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), <span class="hljs-keyword">done</span>.
Resolving deltas: 100% (1/1), <span class="hljs-keyword">done</span>.
</code></pre>
<h2 id="heading-how-to-customize-your-wiki">How to Customize Your Wiki</h2>
<p>Wikis have limited customization options for the sidebar, home page, and footer. But you can extend these options using HTML, CSS, and Markdown.</p>
<p>We have already discussed the home page, and now we'll discuss the footer and sidebar.</p>
<p>The footer and sidebar show or contain helpful links such as contact information, navigation links, social media links, and so on.</p>
<p>The footer is shown at the bottom of every page on your site, and the sidebar is typically a vertical column on the left or right side of a web page. Both are visible on all pages of the wiki.</p>
<h3 id="heading-how-to-create-a-custom-sidebar">How to create a custom sidebar</h3>
<p>There are two ways to create a sidebar in the GitHub wiki.</p>
<ol>
<li>With the GitHub UI</li>
<li>Locally in your IDE</li>
</ol>
<p>We'll look at each method here so you can choose the one that works best for you.</p>
<h4 id="heading-with-the-github-ui">With the GitHub UI</h4>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/sidebar-1.png" alt="Create a sidebar" width="600" height="400" loading="lazy">
<em>Create a sidebar</em></p>
<p>Go to the wiki home page and click on the “Add a custom sidebar” button to create a sidebar in your wiki.</p>
<p>Next, it will redirect you to the editor page to create a sidebar page. In the sidebar file, you can write markdown content such as navigation links, and so on. After that, click the <strong>save button</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-sidebar-page.png" alt="Create _Sidebar.md file in github wiki." width="600" height="400" loading="lazy">
_Create <code>_Sidebar.md</code> file._</p>
<h4 id="heading-locally-in-your-ide">Locally in your IDE</h4>
<p>The second way is to clone your wiki locally and then create a <code>_Sidebar.md</code><br>file in your wiki at the root level using VS Code or any other IDE which you like. </p>
<h3 id="heading-how-to-create-a-custom-footer">How to create a custom footer</h3>
<p>You'll follow basically the same steps as in the sidebar section to create your custom wiki footer.</p>
<h4 id="heading-with-the-github-ui-1">With the GitHub UI</h4>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/footer.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Go to your wiki page and click on the “Add a custom footer” button to create a footer in your wiki.</p>
<p>Next, it will redirect you to the editor page to create a footer. In the footer file, you can write markdown content such as navigation links, and so on. After that, click the <strong>save button</strong>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/footer-editor.png" alt="Image" width="600" height="400" loading="lazy">
<em>Create a footer</em></p>
<h4 id="heading-locally-in-your-ide-1">Locally in your IDE</h4>
<p>The second way is to clone your wiki locally and then create a <code>_Footer.md</code><br>file in your wiki at the root level using VS Code or any other IDE which you like. </p>
<h2 id="heading-what-is-a-page-how-do-you-create-a-new-page-in-the-wiki">What is a Page? How Do You Create a New Page in the Wiki?</h2>
<p>In a wiki, a page has functionality similar to other CMSs, giving you the power to manage your content and documentation.</p>
<p>With the wiki page, you can divide your content or docs into different sections such as installation, configuration, and so on.</p>
<p>To create a new page, click on the new page button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-a-page.png" alt="Create a new wiki page" width="600" height="400" loading="lazy">
<em>Create a new wiki page</em></p>
<p>It redirects you to the editor page, where you can add a title and content. After your writing is finished, click on the save button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/create-a-new-page-with-wiki.png" alt="Create a wiki page" width="600" height="400" loading="lazy">
<em>Create a wiki page</em></p>
<p>Your page looks like this in the wiki after it is published:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/your-installation-page.png" alt="The Wiki page looks like this in the browser after publishing." width="600" height="400" loading="lazy">
<em>The Wiki page looks like this in the browser after publishing.</em></p>
<p>Everybody can access your pages section. Every page you publish is shown in the pages section on your wiki.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/access-the-page.png" alt="The page section shows the published page list." width="600" height="400" loading="lazy">
<em>The page section shows the published page list.</em></p>
<h2 id="heading-how-to-enable-and-disable-collaboration-in-the-wiki">How to Enable and Disable Collaboration in the Wiki</h2>
<p>To enable collaboration for everyone in the wiki, go to your GitHub repository settings page, scroll down, find the features, and unselect the "Restrict editing to collaborators only" checkbox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/access-to-eveyone-in-wiki.png" alt="Enable Collaboration in the GitHub Wiki." width="600" height="400" loading="lazy">
<em>Enable Collaboration in the GitHub Wiki.</em></p>
<p>You can turn off collaboration for everyone, so that you and your team are the only ones responsible for updating, deleting, and editing the wiki.</p>
<p>To do this, you need to restrict editing for other users. Enabling the <strong>Restrict editing to collaborators only</strong> option quickly accomplishes this.</p>
<p>After there haven't been any edits, invite your team and give them access to it. Then just click the "Restrict editing to collaborators only" checkbox.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/enable-it.png" alt="Disable Collaboration in the GitHub Wiki." width="600" height="400" loading="lazy">
<em>Disable Collaboration in the GitHub Wiki.</em></p>
<h2 id="heading-why-is-github-wiki-so-useful">Why is GitHub Wiki So Useful?</h2>
<p>GitHub wikis can be useful for everyone. You can start your documentation with a wiki in less than one minute. You do not need anything to start writing your documentation except basic knowledge of Markdown syntax. </p>
<p>Using GitHub wikis, you can just focus on writing basic documentation and on the project itself. GitHub wiki handles the rest of your documentation such as hosting concerns, search, and so on. Most importantly, for public repository wikis, it's <a target="_blank" href="https://docs.github.com/en/communities/documenting-your-project-with-wikis/adding-or-editing-wiki-pages">totally free</a>. </p>
<p>Many famous open-source projects use Wiki nowadays, such as <a target="_blank" href="https://github.com/facebook/hhvm/wiki">hhvm</a>, <a target="_blank" href="https://github.com/neovim/neovim/wiki">neovim</a>, <a target="_blank" href="https://github.com/guard/guard/wiki">guard</a>, <a target="_blank" href="https://github.com/apple/foundationdb/wiki">foundation db</a>, and others.</p>
<p>Check out the <a target="_blank" href="https://github.com/MyHoneyBadger/awesome-github-wiki">list of projects used in Wiki</a>.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>There are many documentation frameworks on the market, such as Nextra, Lume, Starlight, and Docusaurus. But they take some time to learn, configure, and set up. </p>
<p>Also, if you're still working on your coding skills and you aren't comfortable with tools like React, MDX, and so on, you'll need to take some time to learn them before using these more advanced documentation frameworks.</p>
<p>With GitHub Wiki, you can start creating your documentation right away, and you do not need to worry about deploying and hosting anything managed by GitHub.</p>
<p>GitHub Wiki is a great choice for small and early-stage projects. You and your team can focus on the project while composing straightforward documentation.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Accessible Technical Documentation – Best Practices with Examples ]]>
                </title>
                <description>
                    <![CDATA[ When you're writing technical documentation for a project or a tool you're working on, you'll want it to be accessible. This means that it will cater to and be usable by the diverse global audience on the web. Web accessibility aims to make it possib... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/best-practices-for-writing-accessible-technical-documentation/</link>
                <guid isPermaLink="false">66d84fe57211ea6be29e1b6d</guid>
                
                    <category>
                        <![CDATA[ a11y ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Accessibility ]]>
                    </category>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ EZINNE ANNE EMILIA ]]>
                </dc:creator>
                <pubDate>Thu, 11 Apr 2024 23:03:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/04/20240401_161256_0000.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're writing technical documentation for a project or a tool you're working on, you'll want it to be accessible. This means that it will cater to and be usable by the diverse global audience on the web.</p>
<p>Web accessibility aims to make it possible for anyone to access web content. There are common accessibility best practices for designers, developers, and writers. This article will cover some best practices for creating technical content.‌</p>
<h2 id="heading-what-is-web-accessibility">What is Web Accessibility?</h2>
<p><a target="_blank" href="https://www.freecodecamp.org/news/web-accessibility-for-devs/">Web accessibility</a> is the practice of making it possible for anyone to consume or create content on the web, regardless of any health, economic, geographic, or language challenges they may have.</p>
<h2 id="heading-why-is-web-accessibility-important">Why is Web Accessibility Important?</h2>
<p>It is important to apply web accessibility best practices in your projects for a number of reasons.</p>
<p>First, it'll help you reach a wider audience. When a person who may have different abilities comes across some data on the web – say on your website – they'll want to learn more or use the data. But if they are not able to access it, you will not be happy or have a good experience.</p>
<p>Imagine how many people are unable to utilize the web because they are not considered when devs and designers are making decisions about how the product, website, or tool will be built.</p>
<p>Another important thing about accessibility is that it improves your brand's quality. Letting people know you are an accessibility-oriented person or company by implementing it in your work shows that you want your information to be available t everyone. It also displays your versatility in your craft and your ability to improve and adapt with changing times and trends.</p>
<p>Also, as an individual, applying accessibility best practices benefits you as well. There are possible employment opportunities for developers and designers with great accessibility skills.</p>
<p>Good accessibility practices mean good SEO practices too, which can result in more visibility for your work.</p>
<p>Finally, accessibility is enforced by law in certain countries around the world, and web accessibility strategies are implemented by certain countries. There could be legal consequences if you overlook accessibility on your websites and apps.</p>
<h2 id="heading-how-to-write-accessible-technical-documentation">How to Write Accessible Technical Documentation</h2>
<p>Software engineers have a key role in making the web accessible. But when it comes to writing documentation, technical writers also have a role to play in improving web accessibility.</p>
<p>Technical writers help write various types of content, like user guides, tutorials, API references, code documentation, and so on.</p>
<p>Now, let's look at some of the best practices for implementing web accessibility in technical writing. These strategies will help improve your documentation and make it more user-friendly and accessible to everyone.</p>
<h3 id="heading-use-clear-headings-and-paragraphs">Use clear headings and paragraphs</h3>
<p>When writing content, you should make sure to use headings – along with the proper heading hierarchy (H1 for the title of the page/article, H2 for major headings, H3 for subheadings, and so on).</p>
<p>Also, make sure to break your content up into paragraphs so it's easier to read and understand.</p>
<p>When you introduce a new topic, use a heading to call that out. When you talk about smaller topics within that section, use subheadings to alert the reader.</p>
<p>Headings are also important to help screen readers understand a page's contents and how to navigate through them. So use headings to help guide readers through the text in a logical manner.</p>
<p>You denote headings in markdown with hashes. Here's an example of headings in hierarchical order.‌</p>
<pre><code class="lang-css"># <span class="hljs-selector-tag">Use</span> <span class="hljs-selector-tag">H1</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">page</span> <span class="hljs-selector-tag">title</span>

## <span class="hljs-selector-tag">Use</span> <span class="hljs-selector-tag">H2</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">major</span> <span class="hljs-selector-tag">headings</span> 
<span class="hljs-selector-tag">This</span> <span class="hljs-selector-tag">heading</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">heading</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">section</span> <span class="hljs-selector-tag">content</span>. 

### <span class="hljs-selector-tag">Use</span> <span class="hljs-selector-tag">H3</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">subheadings</span> 
<span class="hljs-selector-tag">This</span> <span class="hljs-selector-tag">heading</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">subheading</span> <span class="hljs-selector-tag">that</span> <span class="hljs-selector-tag">goes</span> <span class="hljs-selector-tag">deeper</span> <span class="hljs-selector-tag">into</span> <span class="hljs-selector-tag">one</span> <span class="hljs-selector-tag">of</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">main</span> <span class="hljs-selector-tag">section</span>'<span class="hljs-selector-tag">s</span> <span class="hljs-selector-tag">points</span>.
</code></pre>
<h3 id="heading-make-your-content-clear-and-concise">Make your content clear and concise</h3>
<p>Overall, try to keep your sentences quite short in your docs. This makes them easier to read and understand (for everyone). You can also use images or videos to provide more details if needed.</p>
<p>Make sure you give the full meanings of any acronyms you are using for the first time. Also, always use simple sentences, and try not to use ambiguous words.</p>
<p>Here's an example of an overly complex, long sentence with difficult vocabulary:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">The</span> <span class="hljs-selector-tag">web3</span> <span class="hljs-selector-tag">running</span> <span class="hljs-selector-tag">on</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">Blockchain</span> <span class="hljs-selector-tag">structure</span> <span class="hljs-selector-tag">which</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">transparent</span>, <span class="hljs-selector-tag">secure</span>, <span class="hljs-selector-tag">immutable</span>, <span class="hljs-selector-tag">decentralized</span> <span class="hljs-selector-tag">would</span> <span class="hljs-selector-tag">require</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">processes</span> <span class="hljs-selector-tag">of</span> <span class="hljs-selector-tag">artificial</span> <span class="hljs-selector-tag">intelligence</span>, <span class="hljs-selector-tag">where</span> <span class="hljs-selector-tag">it</span> <span class="hljs-selector-tag">would</span> <span class="hljs-selector-tag">read</span> <span class="hljs-selector-tag">data</span>, <span class="hljs-selector-tag">process</span>, <span class="hljs-selector-tag">and</span> <span class="hljs-selector-tag">store</span> <span class="hljs-selector-tag">information</span>.
</code></pre>
<p>This is better:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">Web3</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">built</span> <span class="hljs-selector-tag">on</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">transparent</span>, <span class="hljs-selector-tag">secure</span>, <span class="hljs-selector-tag">unchangable</span>, <span class="hljs-selector-tag">and</span> <span class="hljs-selector-tag">decentralized</span> <span class="hljs-selector-tag">structure</span> <span class="hljs-selector-tag">of</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">blockchain</span>. <span class="hljs-selector-tag">It</span> <span class="hljs-selector-tag">uses</span> <span class="hljs-selector-tag">artificial</span> <span class="hljs-selector-tag">intelligence</span> <span class="hljs-selector-tag">processes</span> <span class="hljs-selector-tag">to</span> <span class="hljs-selector-tag">read</span>, <span class="hljs-selector-tag">process</span>, <span class="hljs-selector-tag">and</span> <span class="hljs-selector-tag">store</span> <span class="hljs-selector-tag">information</span>.
</code></pre>
<p>Your content should contain the main points you're trying to make, removing all forms of ambiguity.‌ ‌</p>
<h3 id="heading-use-informative-link-text">Use informative link text</h3>
<p>All your in-line links should use clear, detailed, and descriptive text. You can describe the link's purpose or the company's name if it is a brand, for example.</p>
<p>Links are important for improving the ranking of a page. And using links like "Click here" or "Read More" is not all that helpful, as they don't tell the reader much about what they'll find at that link.</p>
<p>For instance, if I wanted to link a W3C (World Wide Web Consortium) accessibility tutorial to this article, I could use the following format: Check out <a target="_blank" href="https://www.w3.org/WAI/roles/writers/">these resources for content writers by W3C</a>.</p>
<h3 id="heading-add-alt-text-and-captions-to-media-content">Add alt text and captions to media content</h3>
<h4 id="heading-images">Images</h4>
<p>Adding descriptive text to the alt text attribute allows screen readers to be able to read out the alt text associated with an image. Alt text also helps search engine bots that crawl the page know how to classify that content.</p>
<p>When you're adding alt text, describe the purpose of the image and not what the image is. For instance, let's say you're using an image that shows some shipping containers in a section that is about containerization.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/containers-1.jpeg" alt="Various containers on a ship in motion to illustrate the packaging structure and process of a digital container." width="600" height="400" loading="lazy"></p>
<p><em>Various containers on a ship in motion to illustrate the packaging structure and process of a digital container.</em></p>
<p>Instead of writing alt text like "various containers on a ship in motion", you could write "various containers on a ship in motion to illustrate the packaging structure and process of a digital container."</p>
<p>While alt text serves as an alternative for the image, captions give more details about the image. You can use HTML to insert image captions. Markdown does not support image captions, but markdown documentation sites usually have a way around it (for example, through plugins – ReadTheDocs, MkDocs – or inserting HTML via a custom component –Docusaurus).</p>
<p>As an example, I'll show you how to add image captions in Docusaurus.</p>
<p><strong>How to add image captions in a Docusaurus .md file:</strong></p>
<ul>
<li><p>Create a folder <code>components</code> in the <code>src</code> folder.</p>
</li>
<li><p>Create a file named <code>figure.jsx</code>.</p>
</li>
<li><p>Add this line of code to it:</p>
</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">React</span> <span class="hljs-selector-tag">from</span> "<span class="hljs-selector-tag">react</span>"; 
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">useBaseUrl</span> <span class="hljs-selector-tag">from</span> "<span class="hljs-keyword">@docusaurus</span>/useBaseUrl"; 
<span class="hljs-selector-tag">export</span> <span class="hljs-selector-tag">default</span> <span class="hljs-selector-tag">function</span> <span class="hljs-selector-tag">Figure</span>({ src, caption }) {
  return ( 
  &lt;figure&gt; &lt;img src={useBaseUrl(src)} <span class="hljs-selector-tag">alt</span>={caption} /&gt; 
  &lt;<span class="hljs-selector-tag">figcaption</span>&gt;{`<span class="hljs-attribute">Figure</span>: ${caption}`}&lt;/<span class="hljs-selector-tag">figcaption</span>&gt; &lt;/<span class="hljs-selector-tag">figure</span>&gt; 
  ); 
}
</code></pre>
<ul>
<li>Go to the <code>.md</code> file where you have the image and import the code.</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">Figure</span> <span class="hljs-selector-tag">from</span> '<span class="hljs-keyword">@site</span>/src/components/figure'; 
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">figure1</span> <span class="hljs-selector-tag">from</span> '<span class="hljs-selector-tag">path-to-image</span>';
</code></pre>
<ul>
<li>Add it to the file.</li>
</ul>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">Figure</span> <span class="hljs-selector-tag">caption</span>="<span class="hljs-selector-tag">This</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">a</span> <span class="hljs-selector-tag">caption</span> <span class="hljs-selector-tag">for</span> <span class="hljs-selector-tag">the</span> <span class="hljs-selector-tag">image</span>" <span class="hljs-selector-tag">alt</span>="<span class="hljs-selector-tag">This</span> <span class="hljs-selector-tag">is</span> <span class="hljs-selector-tag">alt</span> <span class="hljs-selector-tag">text</span>" <span class="hljs-selector-tag">src</span>={figure1} /&gt;
</code></pre>
<p>The image will now display with a caption.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_13-3.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>A screenshot example of image caption</em></p>
<h4 id="heading-videos">‌Videos</h4>
<p>To caption videos, HTML is a great option. But if you are using markdown, you can embed videos from YouTube and Vimeo using the <code>&lt;iframe&gt;</code> tag. These apps offer in-built caption support so you can enable captions before adding the embed code.</p>
<p>You could also install third-party plugins for this purpose.</p>
<p>Here's another tip: avoid flashing content in your videos as it could lead to seizure triggers. If your video has flashing bright colours, ensure that it does not exceed two times within a second.</p>
<h3 id="heading-add-transcripts-to-audios-and-videos">Add transcripts to audios and videos</h3>
<p>It's a good idea to add transcripts to your audio and video content. Not everyone will want to watch or listen to the content. But they may be curious to know what it is about.</p>
<p>By adding a transcript, you make it easier for anyone to navigate through the content and get the information that they need.</p>
<h4 id="heading-transcript-for-audio">Transcript for audio</h4>
<p>For audio content, you can insert transcripts using HTML. Here's an example:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">audio</span> <span class="hljs-attr">controls</span> <span class="hljs-attr">muted</span>&gt;</span><span class="hljs-comment">&lt;!--Always set your audios to muted--&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"ringtone.mp3"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"audio/mpeg"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">source</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">audio</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">code</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Here is a transcription of the text<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span> 
    00:03 = I am going to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:05 = I am going to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:08 = I am going to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:10 = I need to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:11 = I have to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:13 = I should be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:16 = I am going to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:18 = I ought to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:21 = I have to be productive today<span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
    00:23 = Productivity matters to me <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">code</span>&gt;</span>
</code></pre>
<p>For markdown documentation sites like Docusaurus, you can create a custom component.‌</p>
<ul>
<li><p>In your <code>src/components</code> folder, create a file named <code>transcript.jsx</code>.</p>
</li>
<li><p>Insert this code:</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>; 
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Transcript</span>(<span class="hljs-params">{ }</span>) </span>{ 
  <span class="hljs-keyword">const</span> [showTranscript, setShowTranscript] = useState(<span class="hljs-literal">false</span>); 
  <span class="hljs-keyword">const</span> toggleTranscript = <span class="hljs-function">() =&gt;</span> { 
    setShowTranscript(!showTranscript); 
  }; 
  <span class="hljs-keyword">return</span> ( 
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{toggleTranscript}</span>&gt;</span> { 
    showTranscript ? 'Hide transcript' : 'View transcript'
    } 
    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span> {showTranscript &amp;&amp; ( <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"transcriptText"</span>&gt;</span> (insert your transcript text here) <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> )} 
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span> 
  ); 
}
</code></pre>
<ul>
<li>Go to your markdown file and import it.</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">Transcript</span> <span class="hljs-selector-tag">from</span> '<span class="hljs-keyword">@site</span>/src/components/transcript'; 

&lt;<span class="hljs-selector-tag">Transcript</span> /&gt;
</code></pre>
<p>‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_17-6.png" alt="A screenshot of the audio transcript output on a documentation site" width="600" height="400" loading="lazy"></p>
<p><em>A screenshot of the audio transcript output</em></p>
<p>‌<strong>Note:</strong> I added some tweaks to the code to make transcript display optional. You can edit it if you want the transcript to show as the page loads.</p>
<h4 id="heading-transcript-for-video">Transcript for video</h4>
<p>Now for videos, YouTube is a great option. It provides inbuilt transcripts for your videos. So, you can always embed YouTube videos in your docs.</p>
<p>The transcript is in the video description after the main details. The transcript will display with the timestamps when you click the "Show Transcript" button.</p>
<h3 id="heading-add-code-snippets-and-use-the-colour-contrast-technique">Add code snippets and use the colour contrast technique</h3>
<h4 id="heading-how-to-add-code-snippets">How to add code snippets</h4>
<p>Use code blocks within the text to explain code instead of images. You could also use code snippets to showcase the output of your code. Unless it is necessary to add an image, you should use code snippets.</p>
<p>For instance,</p>
<p><code>index.html</code></p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> 
        <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">"content-type"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"text/html; charset=utf-8"</span> /&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>A calculator app<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> 
        <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span>/&gt;</span> 
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> 
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>This will allow screen readers to read through the code, which they are not able to do with screenshots.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_14-2.png" alt="A screenshot of the above code" width="600" height="400" loading="lazy"></p>
<p><em>A screenshot of the above code</em></p>
<h4 id="heading-colour-contrast-technique">Colour contrast technique</h4>
<p>The colour contrast technique implies using colours that are opposite or heavily contrasting.</p>
<p>For example, using black text on a white background has a high contrast, as opposed to using light brown text on a brown background.</p>
<p>When combining colours, you could use an <a target="_blank" href="http://colorsafe.co/">accessible colour palette like Color Safe</a>.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_15-4.png" alt="Using a pale white colour on a green background gotten from Color Safe" width="600" height="400" loading="lazy"></p>
<p><em>Using a pale white colour on a green background gotten from Color Safe</em></p>
<h3 id="heading-add-translation-options">Add translation options</h3>
<p>There are documentation sites that provide translation options where you can build your docs in multiple languages, websites like Jekyll. <a target="_blank" href="https://leo3418.github.io/collections/multilingual-jekyll-site/add-language-switcher.html">This is an example</a>.</p>
<p>Docusaurus is also another doc site that provides multilingual options using Crowdin or Git.</p>
<ul>
<li><p><a target="_blank" href="https://docusaurus.io/docs/i18n/git">Follow through this guide</a> to set up translation and localization on Docusaurus using Git.</p>
</li>
<li><p><a target="_blank" href="https://docusaurus.io/docs/i18n/crowdin">Follow through this guide</a> to set up translation and localization on Docusaurus using Crowdin.‌</p>
</li>
</ul>
<h3 id="heading-use-accessibility-testing-tools">Use accessibility testing tools</h3>
<p>There are tools you can use to check for errors in accessibility in your docs. Some examples are <a target="_blank" href="https://wave.webaim.org/">WAVE (Web Accessibility Evaluation Tool)</a> and <a target="_blank" href="https://www.deque.com/axe/">AXE (Accessibility Engine)</a>.</p>
<p>Also, you can get the <a target="_blank" href="https://www.nvaccess.org/download/">NVDA(NonVisual Desktop Access) screen reader</a> to test out your content. This software will let you know how the content of your documentation will be perceived by a user using a screen reader.‌</p>
<h3 id="heading-set-up-an-improvement-or-suggestion-box">Set up an improvement or suggestion box</h3>
<p>Finally, it may not be possible to cover the needs of every user. So you could add a suggestion or improvement box, allowing users to send feedback about how you could further improve the content. Hearing firsthand from users can help you know how best to make the docs accessible for them.</p>
<p>To add an improvement box, you could use an external form link that stores the users' inputs or you could set up the suggestion box in the docs.</p>
<h4 id="heading-how-to-add-an-external-form-link-in-docusaurus">How to add an external form link in Docusaurus</h4>
<p>You would need to create a custom component for that.</p>
<ul>
<li><p>Go to <code>src/components</code> folder and create a file <code>feedback.jsx</code>.</p>
</li>
<li><p>Add this code:</p>
</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">React</span> <span class="hljs-selector-tag">from</span> '<span class="hljs-selector-tag">react</span>'; 

<span class="hljs-selector-tag">export</span> <span class="hljs-selector-tag">default</span> <span class="hljs-selector-tag">function</span> <span class="hljs-selector-tag">FeedbackButton</span>({ href }) {
  return ( &lt;a href={href} <span class="hljs-selector-tag">target</span>="_<span class="hljs-selector-tag">blank</span>" <span class="hljs-selector-tag">rel</span>="<span class="hljs-selector-tag">noopener</span> <span class="hljs-selector-tag">noreferrer</span>" &gt; <span class="hljs-selector-tag">Give</span> <span class="hljs-selector-tag">Feedback</span> &lt;/<span class="hljs-selector-tag">a</span>&gt; ); 
};
</code></pre>
<ul>
<li>In your markdown file import it:</li>
</ul>
<pre><code class="lang-css"><span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">FeedbackButton</span> <span class="hljs-selector-tag">from</span> '<span class="hljs-keyword">@site</span>/src/components/feedbackbutton';
</code></pre>
<ul>
<li>Insert the link</li>
</ul>
<pre><code class="lang-css">&lt;<span class="hljs-selector-tag">FeedbackButton</span> <span class="hljs-selector-tag">href</span>="<span class="hljs-selector-tag">https</span>://<span class="hljs-selector-tag">forms</span><span class="hljs-selector-class">.google</span><span class="hljs-selector-class">.com</span>" /&gt;
</code></pre>
<p>When you run it on your docs, it should showcase a link to Google forms. Google Forms is an example, you could add the link to your company website or server. Here's what it'll look like:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/Screenshot_18-3.png" alt="A feedback link that states &quot;Give feedback&quot; for suggestion or improvement on a docusaurus docs site that leads users to an external site which is Google Forms" width="600" height="400" loading="lazy"></p>
<p><em>A feedback link for suggestion in a docs site</em></p>
<h2 id="heading-summary">Summary</h2>
<p>To follow and implement these accessibility best practices, you can consider creating or using an already made style guide. This can help you consistently implement these practices and make it easier for you and other technical writers on your team.</p>
<p>There are style guides focused on accessibility for technical writers, such as the following:</p>
<ol>
<li><p><a target="_blank" href="https://github.com/heyawhite/tech-writing-tools/blob/main/accessibility/style.md">Accessibility style guide by Heyawhite</a></p>
</li>
<li><p><a target="_blank" href="https://developers.google.com/style/accessibility">Write accessible documentation by Google for developers</a></p>
</li>
<li><p><a target="_blank" href="https://styleguide.mailchimp.com/writing-for-accessibility/">Writing for Accessibility by MailChimp content style guide</a></p>
</li>
</ol>
<p>That sums up my tips about web accessibility practices in writing. I'm a technical writer, and you can reach out to me on <a target="_blank" href="https://www.instagram.com/ezinneanneemilia/">Instagram</a> or hire me via <a target="_blank" href="https://www.upwork.com/freelancers/~013e195fa64f8b3456?mp_source=share">Upwork</a>. Thank you for reading.‌</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
