Reference docs hooks

Important

Reference docs hooks are supported from version 1.1.0-beta.28.

Reference docs hooks give you greater control over some parts of integrated Reference docs and let you:

  • Install the "Try it" request interceptor.
  • Override the "Try it" console Authorization panel.
  • Inject custom interactive content into various parts of Reference docs.

Prerequisites

Create a new file _override/ReferenceDocsHooks.tsx in the root of your repository. Make sure to restart your portal dev server.

Example 1: Install the "Try it" request interceptor

export function requestInterceptor(req, operation) {
  console.log('Request:', req, rawOperation);

  // you get the operation model with raw operation info from the OAS definition
  const rawOperation = operation.operationDefinition;

  // you can manipulate headers, e.g. inject header based on req body
  req.headers['x-body-length'] = req.body?.length;

  // you can also change the req URL
  req.url = '/proxy' + req.url;

  return req;
}

Example 2: Preset values of "Try it" parameters based on user claims

import { setParameterValue, setSecurityDetails, getUserClaims } from '@redocly/developer-portal/ui';

export function onInit() {
  const claims = getUserClaims(); // you can use user claims if login is enabled or get value from other place

  // setParameterValue(in, name, value)
  setParameterValue('path', 'petId', 25);
  setParameterValue('header', 'x-user-email', claims?.email);

  setSecurityDetails('api_key', 'sk_123123'); // 'api_key' is the security scheme id from the OAS definition
  setSecurityDetails('my_oauth2', {
    client_id: 'user1',
    client_secret: 'secret123'
  });
}

Example 3: Override the "Try it" console Authorization panel

This is a basic example of the custom Authorization panel which loads a list of apps with API keys based on user identity, and lets the user choose between them.

Add any React component to the _override/ReferenceDocsHooks.tsx file.

The key is to call onChange callback to provide auth details back to Reference docs Try it panel.

import * as React from 'react';
import { useState } from 'react';
import { AuthPanelHookProps, getIdPJwt, getUserClaims, Dropdown } from '@redocly/developer-portal/ui';

export function ReplaceTryItAuthPanel({ operation, server, onChange, OAuth2 }: AuthPanelHookProps) {
  const [error, setError] = useState(null);
  const [apps, setApps] = useState([]);
  const [loading, setLoading] = useState(false);
  const [tokenLoading, setTokenLoading] = useState(false);
  const [selectedAppIdx, setSelectedAppIdx] = useState<any>(-1);

  // let's take the first scheme for example
  const authScheme = operation.security[0].schemes[0];

  const userIdPJwt = getIdPJwt();
  const userClaims = getUserClaims();

  React.useEffect(() => {
    run();
    async function run() {
      setLoading(true);
      try {
        // fetch apps based on user token
        const apps = fetch('...', {
          headers: { Authorization: userIdPJwt }
        });

        setApps(apps);

        setSelectedAppIdx(-1);
        setLoading(false);
      } catch (e) {
        setError(e.message);
        setLoading(false);
      }
    }
  }, []);



  const handleSelect = item => {
    setSelectedAppIdx(item.idx);

    // call onChange to pass auth details back ot reference docs
    // pass string for API Key
    onChange({
      [authScheme.id]: item.accessKy
    });

    // for basic auth
    // onChange({
    //   [authScheme.id]: { username: 'xxx', password: 'xxx' },
    // });

    // for oauth2
    // onChange({
    //   [authScheme.id]: { token: { access_token: 'test' } },
    // });
  };

  if (loading) {
    return 'Loading apps...';
  }

  const options = apps.map((app, idx) => ({ idx, value: app.name, key: app.accessKey }));

  return (
    <div>
      <h4 style={{marginTop: 0}}> Select app: </h4>
      <Dropdown
        fullWidth
        variant="dark"
        onChange={handleSelect}
        value={options[selectedAppIdx]?.value}
        options={options}
      />
      {error}
    </div>
  );
}

Simplify the OAuth2 token exchange with our helper library.

authorizeClientCredentialsauthorizeAuthorizationCodeauthorizeImplicit
OAuth2.authorizeClientCredentials({
  tokenUrl: authScheme.flows.clientCredentials.tokenUrl,
  clientId: apps[selectedAppIdx].client_id,
  clientSecret: apps[selectedAppIdx].client_secret,
  scopes: [],
  successCallback: token => {
    setTokenLoading(false);
    onChange({
      [authScheme.id]: { token },
    });
  },
  errorCallback: e => {
    setTokenLoading(false);
    setError(e.message);
  },
});
OAuth2.authorizeAuthorizationCode({
  authorizationUrl: authScheme.flows.clientCredentials.authorizationUrl,
  tokenUrl: authScheme.flows.clientCredentials.tokenUrl,
  clientId: apps[selectedAppIdx].client_id,
  clientSecret: apps[selectedAppIdx].client_secret,
  scopes: [],
  successCallback: token => {
    setTokenLoading(false);
    onChange({
      [authScheme.id]: { token },
    });
  },
  errorCallback: e => {
    setTokenLoading(false);
    setError(e.message);
  },
});
OAuth2.authorizeImplicit({
  authorizationUrl: authScheme.flows.clientCredentials.authorizationUrl
  clientId: apps[selectedAppIdx].client_id,
  scopes: [],
  successCallback: token => {
    setTokenLoading(false);
    onChange({
      [authScheme.id]: { token },
    });
  },
  errorCallback: e => {
    setTokenLoading(false);
    setError(e.message);
  },
});