Skip to main content

Integrate SDK Snippets into your API Reference Documentation using Docusaurus

This tutorial includes the following SDK languages and versions:

TypeScript v1TypeScript v2JavaPython v1Python v2C#GoPHP

When you expose your API to others, such as a public API for your customers to use, or an internal API for your team to use, you need to provide documentation. Typically you would have a developer portal with generated API documentation, as well as other content such as onboarding guides.

As you then add SDKs to your API, you also need to add SDK documentation. liblab generates SDK documentation snippets from your API spec, and you can then integrate these into your existing documentation site.

This tutorial shows you how to add SDK snippets to an existing API documentation site built with Docusaurus. For this tutorial, we will use the liblab llama store API as an example.

A screenshot of the llama store docs showing the Create API token endpoint and example C# code

Prerequisites

To compete this tutorial you will need:

This tutorial also assumes you have a very basic understanding of web development concepts, and TypeScript or JavaScript. There will only be a small amount of code to write, and it will be provided for you and explained.

Steps

  1. Create a new Docusaurus 2 site
  2. Create API docs
  3. Generate SDK snippets for the llama store API
  4. Add SDK snippets to your Docusaurus site

Create a new Docusaurus 2 site

In this tutorial, you will add SDK snippets to an existing Docusaurus 2 site.

note

Docusaurus 3 is the latest version, but the site we are using will use the Docusaurus OpenAPI plugin, which currently only supports Docusaurus 2. We will update this tutorial when the plugin is updated to support Docusaurus 3.

Create the new site

To make it easier to set this up, we have created a template repo with an empty Docusaurus site.

  1. Select the button below to create a new Docusaurus site repo using this template.

  2. Give your new control repository a name, a description, and make it public or private.

  3. Select Create repository to create the repository from the template.

    The repository that is created has:

    • A Docusaurus site with the default theme
    • The Docusaurus OpenAPI plugin installed
    • A simple home page
  4. Clone this new site locally.

Run the Docusaurus site

Once the repo is cloned, you can run the site to see what it looks like. Currently this will be empty, with just a home page, a header and a footer.

  1. Open the cloned repo in your IDE.

  2. Navigate to the llama-store-docs folder:

    Terminal
    cd llama-store-docs
  3. Run the following command to start the Docusaurus site:

    Terminal
    npm install
    npm run start

This will open your default browser, running the site at http://localhost:3000.

The blank docs site showing a home page that points to this tutorial

Create API docs

The next step is to add API docs from the llama store API to the Docusaurus site. The site you created already uses the Docusaurus OpenAPI plugin - and this can create API docs from an OpenAPI spec.

The repo is configured to load the Llama Store API spec from the llama store GitHub repo. You can see this in the docusaurus.config.js file:

docusaurus.config.js
plugins: [
[
'docusaurus-plugin-openapi-docs',
{
id: "api",
docsPluginId: "classic",
config: {
llamastore: {
specPath: "https://raw.githubusercontent.com/liblaber/llama-store/main/spec.yaml",
outputDir: "docs/API",
sidebarOptions: {
groupPathsBy: "tag",
},
},
}
},
]
],

This configuration also tells the plugin that the API docs need to be created in the docs/API directory.

To generate the API docs, do the following:

  1. From the llama-store-docs directory, run the following command:

    Terminal
    npm run docusaurus gen-api-docs all

    This will create a new folder in the docs directory called API, and create API docs in that folder. These docs are mdx files - markdown files with JSX that Docusaurus can render.

    docs
    └── API
    ├── Introduction.mdx
    ├── sidebar.js
    ├── llama-store-api.info.mdx
    ├── get-llama-picture-by-llama-id.api.mdx
    ├── create-llama-picture.api.mdx
    ├── update-llama-picture.api.mdx
    ├── delete-llama-picture.api.mdx
    ├── get-llamas.api.mdx
    ├── create-llama.api.mdx
    ├── get-llama-by-id.api.mdx
    ├── update-llama.api.mdx
    ├── delete-llama.api.mdx
    ├── create-api-token.api.mdx
    ├── get-user-by-email.api.mdx
    └── register-user.api.mdx
  2. If you stopped the Docusaurus site, restart it:

    Terminal
    npm run start

You will now see the API docs appear on the sidebar. If you didn't stop the site, the page will automatically refresh and the API docs will appear. You can expand this section to see an introduction page, and pages for each endpoint/HTTP method combination.

The docs site showing the endpoints under the API sidebar, with the introduction showing

All of these generated docs come from the OpenAPI spec for the llama store. The Introduction page uses the info/description section from the spec.

On the right-hand side you will see code snippets using different programming languages. These snippets show how to call the API directly in different languages. This is what we will replace with SDK snippets.

A Python snippet showing how to call the API using requests.

Generate SDK snippets for the llama store API

To generate SDK snippets, you need to use the liblab CLI, along with a config file that is configured for snippets. You can find one in the root of the repo you cloned, called liblab.config.json.

This config file is configured for C#, Go, Python, and PHP:

liblab.config.json
{
"languages": [
"csharp",
"go",
"python",
"php"
],
...
}

It is also pointing to the same API spec as the Docusaurus OpenAPI plugin:

liblab.config.json
{
"specFilePath": "https://raw.githubusercontent.com/liblaber/llama-store/main/spec.yaml",
...
}

In addition, this config file has the settings to generate SDk snippets as a JSON file:

liblab.config.json
{
"docs": [
"snippets"
],
"customizations": {
"documentation": {
"snippets": {
"format": "json"
}
}
},
...
}

Snippets can be created as JSON giving one JSON file with all snippets for each SDK language, or as markdown with one markdown file per API endpoint and method. In this case, we are using JSON.

Generate the SDK snippets

To generate the SDK snippets, do the following:

  1. From the root of the cloned repo, run the liblab CLI to generate an SDK with snippets:

    Terminal
    liblab build

This will generate SDKs in the output folder. Under each language folder will be a documentation folder with the snippets:

output
├── csharp
│ └── Documentation/Snippets
│ └── snippets.json
├── go
│ └── documentation/snippets
│ └── snippets.json
├── php
│ └── documentation/snippets
│ └── snippets.json
└── python
└── documentation/snippets
└── snippets.json

Add SDK snippets to your Docusaurus site

To add the SDK snippets to the site, you need to not only add them to the site, but also replace the Docusaurus component that is currently showing the API snippets.

Add the SDK snippets

To add the SDK snippets to your site, you need to copy them into the llama-store-docs/static folder. This is a folder designed for hosting static assets that your site can use, such as fonts or images.

  1. Rename each snippets.json file to include the language name, for example csharp.json:

    output
    ├── csharp
    │ └── Documentation/Snippets
    │ └── csharp.json
    ├── go
    │ └── documentation/snippets
    │ └── go.json
    ├── php
    │ └── documentation/snippets
    │ └── php.json
    └── python
    └── documentation/snippets
    └── python.json
  2. Create a new folder under llama-store-docs/static called snippets, and copy all the JSON files into this folder:

    llama-store-docs
    └── static
    └── snippets
    ├── csharp.json
    ├── go.json
    ├── php.json
    └── python.json

Create a wrapper for the API snippets component

Docusaurus is based around React, a component based library for creating web sites. The UI is made up of components that can be styled, nested and more. For example, the sidebar with the contents is a component, the API reference is a component, and the API snippets is a component and so on.

One of the great features of Docusaurus is swizzling - the ability to either wrap or completely replace a component. For example, you can replace the component that shows the API snippets with one that shows the SDK snippets.

The component we want to swizzle here is the APIExplorer/CodeSnippets component from the Docusaurus OpenAPI plugin. To do this, do the following:

  1. From the llama-store-docs folder, run the following command:

    Terminal
    npm run swizzle docusaurus-theme-openapi-docs ApiExplorer/CodeSnippets -- --wrap --typescript
  2. When prompted, select YES:

    Terminal
    ? Do you really want to swizzle this unsafe internal component? 
    › - Use arrow-keys. Return to submit.
    NO: cancel and stay safe
    ❯ YES: I know what I am doing!
    [Exit]

This will create a wrapper for this component in the src/theme folder:

src
└── theme
└── APIExplorer
└── CodeSnippets
└── index.tsx

The index.tsx file will contain the wrapped component.

src/theme/APIExplorer/CodeSnippets/index.tsx
import React from 'react';
import CodeSnippets from '@theme-original/ApiExplorer/CodeSnippets';
import type CodeSnippetsType from '@theme/ApiExplorer/CodeSnippets';
import type {WrapperProps} from '@docusaurus/types';

type Props = WrapperProps<typeof CodeSnippetsType>;

export default function CodeSnippetsWrapper(props: Props): JSX.Element {
return (
<>
<CodeSnippets {...props} />
</>
);
}

Update the wrapper to show the SDK snippets

To show the SDK snippets, we are going to replace the entire component, and re-use a number of components from the theme.

info

You can find the full code for this in the liblab llama store on GitHub.

  1. In the index.tsx file for the swizzled component, update the imports to the following:

    index.tsx
    import React, { useState } from "react";

    import useDocusaurusContext from "@docusaurus/useDocusaurusContext";

    import ApiCodeBlock from "@theme/ApiExplorer/ApiCodeBlock";
    import CodeTabs from "@theme/ApiExplorer/CodeTabs";
    import type CodeSnippetsType from "@theme/ApiExplorer/CodeSnippets";
    import type Language from "@theme/ApiExplorer/CodeSnippets/code-snippets-types";
    import type { WrapperProps } from "@docusaurus/types";

    This imports the components we need to show the SDK snippets.

  2. Above the generated CodeSnippetsWrapper function, add the following function:

    index.tsx
    /**
    * Renders a code tab component.
    *
    * This is a tab designed to contain code snippets, and is styled to
    * show the language icon and name. This is a child of the CodeTabs
    * component available from the OpenAPI plugin theme.
    *
    * @param children - The content to be displayed within the code tab.
    * @param hidden - A boolean indicating whether the code tab should be hidden.
    * @param className - Additional CSS classes to be applied to the code tab.
    * @returns The JSX element representing the code tab.
    */
    function CodeTab({ children, hidden, className }: any): JSX.Element {
    return (
    <div role="tabpanel" className={className} {...{ hidden }}>
    {children}
    </div>
    );
    }

    This defines a function that returns a React component for a code tab. These tabs are styled to have the language name and icon at the top.

  3. Below this function, add the following:

    index.tsx
    /**
    * Renders a language code tab. This creates a code tab, with an API code block
    * containing the code snippet for the language.
    *
    * @param language - The language object to render the code tab for.
    */
    function LanguageCodeTab(language: Language): JSX.Element {
    return (
    <CodeTab
    value={language.language}
    label={language.language}
    key={language.language}
    attributes={{
    className: `openapi-tabs__code-item--${language.logoClass}`,
    }}
    >
    {/* @ts-ignore */}
    <ApiCodeBlock
    language={language.highlight}
    className="openapi-explorer__code-block"
    showLineNumbers={true}
    >
    {language.sample}
    </ApiCodeBlock>
    </CodeTab>
    );
    }

    This declares a function to render a language code tab, using the CodeTab component you just declared. Inside the code tab is an ApiCodeBlock, which is a component from the OpenAPI plugin theme that shows code snippets with appropriate syntax highlighting. The code block shows the {language.sample} - the code sample on the Language that is passed to this function. The Language object represents an SDK language, with the language name that is used to style the tabs, and the code sample.

  4. Under this new function, add the following:

    index.tsx
    /**
    * Loads the code snippets for the given language and sets it as the sample on the language object.
    *
    * @param language - The language object to load the snippets for.
    * @param props - The component props.
    */
    function GetSnippetsForLanguage(language: Language, props: Props) {
    // load the snippets
    const snippets = require(`/snippets/${language.language}.json`);

    // convert the current API endpoint to the snippet name
    // in the same format as the snippets.
    // In this case, path parameters in the path name are `:name`,
    // such as `:llamaId`, and we need these as `{llamaId}`.
    var endpoint = props.postman.url.path
    .map((p: string) => p.startsWith(":") ? `/{${p.replace(":", "")}}` : `/${p}`)
    .join("");

    // Get the sample and set it on the language object
    language.sample = snippets.endpoints[endpoint][props.postman.method.toLowerCase()];
    }

    This defines a function to load the SDK snippets for each language object. This reads the relevant snippets JSON from the static folder, and extracts the relevant code snippet for the current API endpoint and method.

    To retrieve the snippet, the endpoint needs to be formatted to match the JSON structure. The Docusaurus OpenAPI plugin has the endpoint in an array of path components as strings, and indicates which ones are path parameters with a colon, such as :llamaId. For example, the Get Llama method would be in the path as:

    `["llama", ":llama_id"]`.

    In the snippet JSON, the relevant snippet would be:

    {
    "endpoints": {
    "/llama/{llama_id}": {
    "get": "<The code snippet for the get method>"
    }
    }
    }

    To get this value, we need to join the paths with a / between each one, and wrap any path parameters with curly braces. This code does this, then uses the endpoint and method to get the relevant snippet from the JSON, and set it on the language object so that the code tab can render it.

  5. Finally, update the CodeSnippetsWrapper function to load the languages, get the snippets for them, and render code tabs:

    index.tsx
    /**
    * Renders the CodeSnippetsWrapper component.
    *
    * This is a wrapper for the swizzled CodeSnippets component, which
    * replaces the original component with a simpler one that shows
    * code snippets for the SDKs generated by liblab.
    *
    * @param {Props} props - The component props.
    * @returns {JSX.Element} The rendered component.
    */
    export default function CodeSnippetsWrapper(props: Props): JSX.Element {
    const { siteConfig } = useDocusaurusContext();

    // Get the language tabs from the site config
    const langs = [...(siteConfig?.themeConfig?.languageTabs as Language[])];

    // Get the code snippet data for the selected language
    // These come from a generated JSON file in the static/snippets folder
    langs.forEach((language) => GetSnippetsForLanguage(language, props));

    // Set up state for the variant and sample - these are not used here,
    // but are required by the CodeTabs component from the OpenAPI plugin theme
    const [selectedVariant, setSelectedVariant] = useState<string | undefined>();
    const [selectedSample, setSelectedSample] = useState<string | undefined>();

    // Set up state for the language - this is used to track the currently
    // selected language
    const [language, setLanguage] = useState(() => langs[0]);

    // Render the code tabs with the language samples
    return (
    <>
    <CodeTabs
    groupId="code-samples"
    action={{
    setLanguage: setLanguage,
    setSelectedVariant: setSelectedVariant,
    setSelectedSample: setSelectedSample,
    }}
    languageSet={langs}
    lazy
    >
    {langs.map((lang) => LanguageCodeTab(lang))}
    </CodeTabs>
    </>
    );
    }

    This function starts by loading the language list - this is defined in the docusaurus.config.json file - in the template repository this is already configured using the list of SDK languages that liblab supports.

    It then uses the GetSnippetsForLanguage function that was defined earlier to load the snippets for each language.

    Next it sets up some state functions that the CodeTabs component needs. Two of these are not used here - the original plugin theme has variants for different ways to call the API for example. The one that is used is the language state, which tracks the currently selected language.

    Finally it renders the code tabs for the languages, using the LanguageCodeTab function to render each one.

Test the SDK snippets

At this point, everything should be set up. You can now test the SDK snippets by running the Docusaurus site.

  1. If you stopped the Docusaurus site, restart it:

    Terminal
    npm run start
  2. From your browser, navigate to any API call. The API snippets are now replaced with SDK snippets.

    A Python snippet showing how to call the SDK.

🎉🎉🎉   Congratulations, you have implemented liblab SDK Snippets into API Reference Documentation using Docusaurus!   🎉🎉🎉

Conclusion

In this tutorial, you have integrated SDK snippets into an existing Docusaurus site. You can see an example of this in action in the liblab llama store](https://github.com/liblaber/llama-store).