prism icon indicating copy to clipboard operation
prism copied to clipboard

honor x-schema-faker settings when mocking from Ninja (aka hosted)

Open EdVinyard opened this issue 3 years ago • 1 comments

follow-up to investigate Pass x- settings to Prism when mocking from Ninja

Goal

When a workspace-project-branch OAS specification includes x-schema-faker options, the mock responses to ninja by the mocks component should honor those options.

Two possible implementation strategies, both with significant drawbacks:

  1. Pass a pre-configured JSF instance into Prism's mock() function. In mocks, cache pre-configured JSF instances based on workspace-project-branch, and figure out how to invalidate this cache when each specification changes. Drawback: This exposes Prism implementation details (that JSF is used) to its client, mocks.

  2. Introduce the concepts of workspace, project, and branch into Prism (or at the very least the notion of distinct Prism configurations). This also requires that the configuration (or a placeholder/key) be supplied along with requests. Drawback: Prism should not know anything about multiple configurations, especially regarding workspaces, projects, and branches.

Note: This probably requires changes to both mocks and prism regardless of the implementation strategy.

Background

mocks uses prism to generate mock reponses. prism in turn uses json-schema-faker (JSF). Specifically, prism:

  • uses a single, global instance of JSF,
  • lacks any contextual knowledge (workspace, project, or branch), and
  • isn't passed any "top level" specification information that could be used to configure the JSF instance appropriately

The current code-path is traced in detail below.

in mocks, handleRequest()

in platform-internal/packages/mocks/src/index.ts, handleRequest() calls validateInputAndMock()

    function handleRequest(
      req: IncomingMessage,
      { workspaceSlug, projectSlug, serviceNodeId, 
        prismUrl, branchName: branch }: ApiLocationInfo,
      config: IHttpOperationConfig,
    ) {
      ...

      TE.bindW('response', ({ input, resolved }) => TE.fromEither(validateInputAndMock(resolved, input, config)(logger))),
      ...

in mocks, validateInputAndMock()

in platform-internal/packages/mocks/src/index.ts, validateInputAndMock() calls mock()

    import mock from '@stoplight/prism-http/dist/mocker';

    function validateInputAndMock(
      resource: IHttpOperation, 
      element: IHttpRequest, 
      config: IHttpOperationConfig
    ) {
      logger.error('validateInputAndMock()');
      return pipe(
        validateInput({ resource, element }),
        E.fold<IPrismDiagnostic[], unknown, IPrismDiagnostic[]>(
          validations => validations,
          () => [],
        ),
        validations => mock({ 
          resource, 
          input: { data: element, validations }, 
          config 
        }),
      );
    }

in prism, mock()

Notice that Prism lacks any concept of workspaces, projects, or branches. Furthermore, Prism lacks any way to retrieve that information.

in prism/packages/http/src/mocker/index.ts, mock() calls generate()

    import { generate, generateStatic } from './generator/JSONSchema';

    const mock = (...) => {
      const payloadGenerator: PayloadGenerator = config.dynamic
        ? partial(generate, resource['__bundled__'])
        : partial(generateStatic, resource);      
    }

Prism uses a single, global instance of json-schema-faker (JSF). This works well when it's started from the command line, but when run from mocks, we need a JSF instance configured per workspace-project-branch.

in prism, generate()

in prism/packages/http/src/mocker/generator/JSONSchema.ts, generate() calls json-schema-faker's generate()

    import * as jsf from 'json-schema-faker';

    jsf.extend('faker', () => faker);
    jsf.option({
      failOnInvalidTypes: false,
      failOnInvalidFormat: false,
      alwaysFakeOptionals: true,
      optionalsProbability: 1 as any,
      fixedProbabilities: true,
      ignoreMissingRefs: true,
      maxItems: 20,
      maxLength: 100,
    });

    generateKeyPair(...) {
      jsf.generate( ... )
    }

gz#8423

(related to Zendesk ticket #8423)

gz#6772

(related to Zendesk ticket #6772)

gz#8775

(related to Zendesk ticket #8775)

gz#9701

(related to Zendesk ticket #9701)

EdVinyard avatar Nov 24 '21 17:11 EdVinyard

Consider:

  • Option 1, w/o cache: 8
  • If performance is bad, add cache: 5

ryotrellim avatar Nov 30 '21 16:11 ryotrellim