Integrate SDK Snippets into your API Reference Documentation using Docusaurus
This tutorial includes the following SDK languages and versions:
TypeScript v1 TypeScript v2 Java v1 Java v2 Python v1 Python v2 C# Go PHP ❌ ✅ ❌ ✅ ❌ ✅ ✅ ✅ ✅
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.
Prerequisites
To compete this tutorial you will need:
- The liblab CLI installed and logged in
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
- Create a new Docusaurus 2 site
- Create API docs
- Generate SDK snippets for the llama store API
- 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.
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.
-
Select the button below to create a new Docusaurus site repo using this template.
-
Give your new control repository a name, a description, and make it public or private.
-
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
-
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.
-
Open the cloned repo in your IDE.
-
Navigate to the
llama-store-docs
folder:Terminalcd llama-store-docs
-
Run the following command to start the Docusaurus site:
Terminalnpm install
npm run start
This will open your default browser, running the site at http://localhost:3000.
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:
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:
-
From the
llama-store-docs
directory, run the following command:Terminalnpm run docusaurus gen-api-docs all
This will create a new folder in the
docs
directory calledAPI
, and create API docs in that folder. These docs aremdx
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 -
If you stopped the Docusaurus site, restart it:
Terminalnpm 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.
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.
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:
{
"languages": [
"typescript",
"csharp",
"go",
"python",
"php"
],
...
}
It is also pointing to the same API spec as the Docusaurus OpenAPI plugin:
{
"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:
{
"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:
-
From the root of the cloned repo, run the liblab CLI to generate an SDK with snippets:
Terminalliblab build
This will generate SDKs in the output
folder. Under each language folder will be a documentation folder with the snippets:
output
├── typescript
│ └── documentation/snippets
│ └── snippets.json
├── 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.
-
Rename each
snippets.json
file to include the language name, for examplecsharp.json
:output
├── typescript
│ └── documentation/snippets
│ └── typescript.json
├── csharp
│ └── Documentation/Snippets
│ └── csharp.json
├── go
│ └── documentation/snippets
│ └── go.json
├── php
│ └── documentation/snippets
│ └── php.json
└── python
└── documentation/snippets
└── python.json -
Create a new folder under
llama-store-docs/static
calledsnippets
, and copy all the JSON files into this folder:llama-store-docs
└── static
└── snippets
├── typescript.json
├── 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:
-
From the
llama-store-docs
folder, run the following command:Terminalnpm run swizzle docusaurus-theme-openapi-docs ApiExplorer/CodeSnippets -- --wrap --typescript
-
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.
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.
You can find the full code for this in the liblab llama store on GitHub.
-
In the
index.tsx
file for the swizzled component, update the imports to the following:index.tsximport 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.
-
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.
-
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 anApiCodeBlock
, 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 theLanguage
that is passed to this function. TheLanguage
object represents an SDK language, with the language name that is used to style the tabs, and the code sample. -
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, theGet 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. -
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 thelanguage
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.
-
If you stopped the Docusaurus site, restart it:
Terminalnpm run start
-
From your browser, navigate to any API call. The API snippets are now replaced with SDK snippets.
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).