rapi-doc / RapiDoc

RapiDoc -WebComponent for OpenAPI Spec
https://rapidocweb.com
MIT License
1.71k stars 285 forks source link

RapiDoc Features #428

Open mrin9 opened 3 years ago

mrin9 commented 3 years ago

Highlighting some of RapiDoc's features as these may be helpful for making a decision if RapiDoc is the right tool

I have included links of some examples below, sources of all of them can be found at https://github.com/rapi-doc/RapiDoc/tree/master/docs/examples and the OpenAPI specs used by the examples can be found at https://github.com/rapi-doc/RapiDoc/tree/master/docs/specs

RapiDoc Features

Theming and Customization

One of the main advantage of RapiDoc is its powerful customization. RapiDoc do not put any text that indicates the documentation is rendered using RapiDoc, you can completely replace the logos with your own, colors, fonts and theme can be changed to match with your own brand. Below are some of the feature that’s usually used

Three Different Presentation Styles

Hide/Show Sections to restrict or enable functionality

2 Beautiful Schema Presentation style

Search and Filter Functionality

Authentication

Built In API console

Not a premium feature, in fact we do not have any premium product.

Markdown

Supports Open Schema Composition

HTML, JavaScript and CSS Injection

Sometimes markdown is not enough to achieve, what’s needed. For those situations you can inject your own functionality using JS , HTML and CSS.

It also allows you to present the same spec with different, content to different section of users You can use JS to add functionality, such as provide a button inside the document that can automatically authenticate your user HTML Injection Example

RapiDoc’s Vendor Extensions

Microservices support

Micro-services architecture may end up generating several OpenAPI spec, each with few Operations, However for the purpose of documentation you may want to list all these Specs in a single integrated view and should appear as a single spec. Thats possible with RapiDoc. For an inspiration have a look at this example - https://www.northbricks.io/apis/ , which appears to be a single documentation but is made with multiple instance of RapiDoc , each rendering a separate OpenAPI spec. (VIew source from browser to check implementation)

Framework Agnostic

All the above listed feature is programmable, You may check our API section to see how you can use these feature programatically. This isn’t a React, Angular or Vue component, But a standard natively supported Web Component and therefore can be accessed and integrated with any framework or just using a plain javascript without any other library

Here is a RapiDoc API Playground where we use plain JavaScript to dynamically make changes to the RapiDoc

francipvb commented 2 years ago

Hello,

What about typescript definitions?

I tried to use rapidoc in a typescript react project without success.

Brian-McBride commented 2 years ago

@francipvb Same problem. I started working on a wrapper for use in react:

/* eslint-disable @typescript-eslint/no-explicit-any */
import React from 'react';
import 'rapidoc';

interface RapiDocProps
  extends React.DetailedHTMLProps<
    React.HTMLAttributes<HTMLDivElement>,
    HTMLDivElement
  > {
  // General
  'spec-url': string;
  'update-route'?: boolean;
  'route-prefix'?: string;
  'sort-tags'?: boolean;
  'sort-endpoints-by'?: 'path' | 'method' | 'summary' | 'none';
  'heading-text'?: string;
  'goto-path'?: string;
  'fill-request-fields-with-example'?: boolean;
  'persist-auth'?: boolean;
  // UI Colors and Fonts
  theme?: 'light' | 'dark';
  'bg-color'?: string;
  'text-color'?: string;
  'header-color'?: string;
  'primary-color'?: string;
  'load-fonts'?: boolean;
  'regular-fonts'?: string;
  'mono-fonts'?: string;
  'font-size'?: 'default' | 'large' | 'largest';
  // Navigation
  'use-path-in-nav-bar'?: boolean;
  'nav-bg-color'?: string;
  'nav-text-color'?: string;
  'nav-hover-bg-color'?: string;
  'nav-hover-text-color'?: string;
  'nav-accent-color'?: string;
  'nav-item-spacing'?: 'default' | 'compact' | 'relaxed';
  // UI Layout & Placement
  layout?: 'row' | 'column';
  'render-style'?: 'read' | 'view' | 'focused';
  'on-nav-tag-click'?: 'expand-collapse' | 'show-description';
  'schema-style'?: 'tree' | 'table';
  'schema-expand-level'?: number;
  'schema-description-expanded'?: boolean;
  'schema-hide-read-only'?: 'always' | 'never' | string;
  'default-schema-tab'?: 'model' | 'example';
  'response-area-height'?: string;
  // Hide/Show Sections
  'show-info'?: boolean;
  'info-description-headings-in-navbar'?: boolean;
  'show-components'?: boolean;
  'show-header'?: boolean;
  'allow-authentication'?: boolean;
  'allow-spec-url-load'?: boolean;
  'allow-spec-file-load'?: boolean;
  'allow-spec-file-download'?: boolean;
  'allow-search'?: boolean;
  'allow-advanced-search'?: boolean;
  'allow-try'?: boolean;
  'allow-server-selection'?: boolean;
  'allow-schema-description-expand-toggle'?: boolean;
  // API Server & calls
  'server-url'?: string;
  'default-api-server'?: string;
  'api-key-name'?: string;
  'api-key-location'?: 'header' | 'query';
  'api-key-value'?: string;
  'fetch-credentials'?: 'omit' | 'same-origin' | 'include';
  // Events
  beforeRender?: (spec: any) => void;
  specLoaded?: (spec: any) => void;
  beforeTry?: (request: any) => any;
  afterTry?: (data: any) => any;
  apiServerChange?: (server: any) => any;
}

declare global {
  interface HTMLElementTagNameMap {
    'rapi-doc': HTMLDivElement;
  }
  /* eslint-disable @typescript-eslint/no-namespace */
  namespace JSX {
    interface IntrinsicElements {
      'rapi-doc': RapiDocProps;
    }
  }
}

export const RapiDocReact = React.forwardRef<HTMLDivElement, RapiDocProps>(
  (
    {
      beforeRender,
      specLoaded,
      beforeTry,
      afterTry,
      apiServerChange,
      children,
      ...props
    }: RapiDocProps,
    ref
  ) => {
    const localRef = React.useRef<HTMLDivElement>(null);

    React.useEffect(() => {
      const rapiDocRef =
        typeof ref === 'object' && ref?.current
          ? ref?.current
          : localRef.current;

      const handleBeforeRender = (spec: any) => {
        beforeRender && beforeRender(spec);
      };

      const handleSpecLoaded = (spec: any) => {
        specLoaded && specLoaded(spec);
      };

      const handleBeforeTry = (request: any) => {
        beforeTry && beforeTry(request);
      };

      const handleAfterTry = (data: any) => {
        afterTry && afterTry(data);
      };

      const handleApiServerChange = (server: any) => {
        apiServerChange && apiServerChange(server);
      };

      console.log(`rapiDocRef`, rapiDocRef);
      if (rapiDocRef) {
        beforeRender &&
          rapiDocRef.addEventListener('before-render', handleBeforeRender);
        specLoaded &&
          rapiDocRef.addEventListener('spec-loaded', handleSpecLoaded);
        beforeTry && rapiDocRef.addEventListener('before-try', handleBeforeTry);
        afterTry && rapiDocRef.addEventListener('after-try', handleAfterTry);
        apiServerChange &&
          rapiDocRef.addEventListener(
            'api-server-change',
            handleApiServerChange
          );
      }
      return () => {
        if (rapiDocRef) {
          beforeRender &&
            rapiDocRef.removeEventListener('before-render', handleBeforeRender);
          specLoaded &&
            rapiDocRef.removeEventListener('spec-loaded', handleSpecLoaded);
          beforeTry &&
            rapiDocRef.removeEventListener('before-try', handleBeforeTry);
          afterTry &&
            rapiDocRef.removeEventListener('after-try', handleAfterTry);
          apiServerChange &&
            rapiDocRef.removeEventListener(
              'api-server-change',
              handleApiServerChange
            );
        }
      };
    }, [
      ref,
      localRef,
      specLoaded,
      beforeRender,
      beforeTry,
      afterTry,
      apiServerChange,
    ]);

    return (
      <rapi-doc {...props} ref={ref || localRef}>
        {children}
      </rapi-doc>
    );
  }
);

export default RapiDocReact;

Then you can use it like:

export function Example() {
  return (
    <RapiDocReact
      specLoaded={(spec) => {
        console.log(spec);
      }}
      show-header={false}
      spec-url="https://petstore.swagger.io/v2/swagger.json"
      render-style="read"
      theme="dark"
      style={{ height: '100vh', width: '100%' }}
    />
  );
}

export default Example;
meiyananthamp commented 1 year ago

how to change the markdown styles. for ex: If i need to style the table,what is the approach?

sberwal commented 1 year ago

@mrin9 Hi Mrinmoy, pls can you update examples for the filtering functionality, specifically to hide certain operations for specific users?

Thanks

bherr2 commented 4 months ago

It'd be great if you could generate other syntaxes than curl. This is useful, but generating a fetch call would also be useful for developers.