Skip to main content
Version: Node.js: 2.x (unmaintained)

How Scribe Works

Read this page if you want a deeper understanding of how Scribe works (for instance, for the purpose of contributing).

When you run generate for the first time​

Here's a high-level overview of what Scribe does on first run:

  1. The appropriate entrypoint file for your framework is located and run by npm (Adonis, Express, Restify).

  2. Each entrypoint's job is to extract the routes from your API and pass them to the core Scribe tool, along with any settings and strategies specific to the framework. Each framework has its own entrypoint, because the process of fetching the routes is different for each:

    • Adonis gives us the Route object that makes this easy:
      const Route = use('Route');
      const endpoints = Route.list();
    • For Express and Restify, we use a decorator that wraps their internal APIs, intercepts any route definitions (eg app.get(...)) and records them. You can learn more about that here.

    Additionally, the entrypoint also figures out the serverStartCommand, the command it must run to start your app locally (such as node server.js). This is needed in case we need to make response calls.

    The entrypoint also attaches some custom extraction strategies to the config. For instance, the Adonis endpoint adds a strategy that allows it to extract URL parameters from the Adonis Route API. These strategies are framework-specific, so they are not a part of the main package, only added dynamically when generating.

    All this information is passed to the core package's generate function:

    const config = require('.scribe.config');
    config.strategies.urlParameters = [
    'strategies/url_parameters/adonis_route_api',
    ...config.strategies.urlParameters
    ];
    const { generate } = require('@knuckleswtf/scribe');
    await generate(endpoints, config, 'adonis', `node ${path.resolve('server.js')}`, {
    force: options.force,
    verbose: options.verbose
    });
  3. Next, the generate function filters the routes to the ones you specified in your config, then processes each route, using the specified strategies to extract info about it—metadata (eg name and description), parameters, and sample responses.

    let parsedEndpoints = await extractor.extract(routes);
  4. After that, the endpoints are grouped (based on their @group tags). The grouping makes it easy for Scribe to loop over them and generate the output.

    let groupedEndpoints = camel.groupEndpoints(parsedEndpoints);

    The grouped endpoints are written to a bunch of YAML files, in a .scribe/endpoints directory in your app. We don't need them right now, but we'll come back to those files later. See What are those YAML files for?

    Alright, the extraction phase is done. Over to output.

  5. When it's time for output, we call the Writer class, and pass in those grouped endpoints. It uses a couple of EJS templates to generate the HTML output.

  6. Finally, the writer copies the generated HTMl, plus the included CSS and JS to your configured static.output_path folder (typically public/docs), and your docs are ready!

    If you enabled Postman or OpenAPI generation, the writer will also generate those.

On subsequent runs​

On subsequent runs, the same thing happens. The only difference is that Scribe first checks to see if there are any YAML files present. If there are, it merges whatever it finds there with what it can extract from your endpoints.

Now, about those YAML files...

What are those YAML files for?​

Earlier, we said that the grouped endpoints are written to some YAML files, in a .scribe/endpoints directory in your app. Each group of endpoints goes into one file, and looks like this:

<your-app>/.scribe/endpoints/0.yaml
name: 'Name of the group'
description: A description for the group.
endpoints:
- httpMethods: ["POST"]
uri: api/stuff
metadata:
title: Do stuff
description:
authenticated: false
headers:
Content-Type: application/json
urlParameters: []
queryParameters: []
bodyParameters:
a_param:
name: a_param
description: Something something
required: true
example: something
type: string
responses:
- status: 200
content: '{"hey": "there"}'
headers: []
description: '200, Success'
responseFields: []

Internally, we call these Camel files, and they're very useful! They're intermediate output, which means they let you modify the data Scribe has extracted, before Scribe goes on to convert to HTML. This means:

  1. You can edit an endpoint's details. For instance, if Scribe made a mistake, or wasn't able to figure out some data, you can just find the YAML file and edit it. Then when you run scribe:generate again, Scribe will use your changes instead of what it figured out.
tip

You can run php artisan scribe:generate --no-extraction for Scribe to completely skip the extraction step and just use the YAML files.

  1. You can sort your endpoints. If you want one endpoint to appear before another, just edit the endpoints key in the YAML and arrange them how you prefer.

  2. You can also sort groups. You'll notice the example above is 0.yaml. To sort groups, just rename the files how you wish, since it's one group per file. For instance, if I rename this file to 1.yaml, and another file to 0.yaml, that group will appear before this one in the docs.

  3. You can add new endpoints. This is useful if you're using a package that adds extra routes, and you want to document those. Custom endpoint files use a slightly different format from regular endpoints, so Scribe automatically adds an example custom.0.yaml file to the .scribe/endpoints folder, and you can edit it to add additional endpoints.

The .scribe folder​

The .scribe folder contains intermediate output—information about your API that Scribe has extracted.

.scribe/
|- endpoints/
|- 0.yaml
|- 1.yaml
|- custom.0.yaml
|- endpoints.cache/
|- 0.yaml
|- 1.yaml
|- auth.md
|- intro.md
|- .filehashes

  • The endpoints folder holds the endpoints information as YAML files. You can edit them to add/overwrite endpoints.
  • The endpoints.cache folder also holds endpoints information, but these files are not meant to be edited by the user. Scribe uses the files here to figure out when you've edited something in endpoints.
  • The auth.md and intro.md files contain the generated text for the "Authentication" and "Introduction" section of your docs. You can edit these.
  • The .filehashes file is how Scribe keeps track of changes you make to auth.md and intro.md.

Scribe regenerates the .scribe folder on every run, while preserving any changes you've made to endpoints or Markdown files. Special cases:

  • When you specify --no-extraction, Scribe will not go through an extraction phase or regenerate the folder. Instead, it will use the information here to generate the output (HTML, Postman, OpenAPI).
  • When you specify --force, Scribe will overwrite your changes to this folder.