Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor parsing and general refinements to configuration / generated Swagger #67

Merged
merged 45 commits into from
Jun 4, 2020

Conversation

danielsharvey
Copy link
Collaborator

@danielsharvey danielsharvey commented May 15, 2020

Work in progress:

  • Refactor from using parsing of config/routes.js directly to parsing only of ‘router:bind’ events which contain all the same information and additional routes including blueprints and custom routes added by hooks etc.
  • Improve capability to set Swagger, such as tags, for all actions within a Sails Controller or Model.
  • Improve documentation of merging of Swagger definitions from various places it may be added.
  • Add additional ‘transformations’ phase to processing: parse —> transform —> generate (better code structure and testing)
  • Add support for blueprint shortcut routes (if present)
  • Update Typescript schemas to further support OpenAPI 3
  • Update Sails Typescript schemas for model/attribute definitions and correct related generation errors
  • Add capability to exclude controllers/models/actions from the generated Swagger / OpenAPI
  • Refactor loading/parsing of controller files to utilise same mechanism as Sails itself (results in better handling of edges case with case sensitivity of filenames and related)
  • Correct handing of “required” attributes in update blueprints (moved to fix: Update blueprint request body schema should not specified 'required' #71)
  • Report warnings for actions (in swagger elements or JSDoc @swagger tags) that do not exist
  • Add support for Sails validations within actions2 inputs
  • Add default tags for both models and controllers (see auto generate tags for routes with model or just controllers #59)

Replacing return type for `generateAttributeSchema()` with
OpenApi.UpdatedSchema causes tsc error, probably due to elements like
`allOf`.

Proposal is refactor UpdatedSchema more fully based on OpenAPI 3.

Also refactor old and unused schema field `common_name`.
Refactor path generation to access model association information
(FK attributes + schemas etc) via the original model definition
rather than a copy in the route information.

As part of this, add association to Sails Model interface.
Includes minor fix to attribute property mapping (Sail --> Swagger).
Includes:
- Add handling of `regex` validation as Swagger `pattern`.
- Fix handling of `isInteger`.
- Fix handling of description; include both model/collection description
  **and** other provider Sails/Swagger descriptions.
- Fix handling over extra 'annotations' (e.g. autoincrement) which
  overwrote description.
WIP - some of the new interfaces are not utilised / fully utilised.

Add `exclude` boolean to annotate Sails actions (Swagger Operations)
to be excluded from generated Swagger.

Refactor controller file Swagger to include `controller` element
containing documentation to be applied to **all** actions in the file
e.g. tags.

Refactor model file Swagger to include `model` element containing
documentation to be applied to **all** blueprint actions for the model
e.g. tags.

Refactor model attribute Swagger to include `meta.swagger` for
applying documentation to individual attributes.

Refactor model attribute Swagger to include `meta.swagger.exclude` for
excluding individual attributes from the generated Swagger.

Add partial Typescript definition for `npm install include-all`.
Includes new proposed model using the `meta.swagger` attribute on
actions2 inputs and exits.

Includes `outputExample` attribute for actions2 exits.
Part of add additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Separate:
1. Parsing of Sails runtime models (`sails.models`), and
2. Loading and parsing of JSDoc from model source files.

Add generation of default tags for models and incorporate into
Swagger generation.

Refactor integration test to compare Swagger JSON object (rather
than string) as test output is a far more helpful diff.

Correct `parseModels()` test data to be models dictionary rather
than array.
Part of add additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Add updated integration test fixture (generated Swagger output).
Part of add additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Add generation of default tags for models and incorporate into
Swagger generation.

Add updated integration test fixture (generated Swagger output).
@danielsharvey
Copy link
Collaborator Author

Some background notes: The need the merge custom routes with bound routes introduced complexity in that there was no single source of truth. Issues matching actions between the two, and handling the flattening that Sails performs in terms of case sensitivity for action identities needed to be handled.

This PR re-examined the Sails 'router:bind' events and the Sails 'controller loading' process. It deals with both to produce a more consistent mechanism with no (less) tricky edge cases.

Part of add additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Refactor SwaggerRouteInfo as the primary 'route' data structure:
- Remove some data better looked up as req (models, associations, tags)
- Refactor information stored re actions / action types.

Refactor from using parsing of `config/routes.js` directly to parsing
of only ‘router:bind’ events which contain all the same information
and additional routes including blueprints and custom routes added
by hooks etc.

Replaces the 'withoutSwaggerRoutes' process with loading process
based on Sails internal process and merges Swagger elements
(including JSDoc).

Background: The need the merge custom routes with bound routes
introduced complexity in that there was no **single** source of truth.
Issues matching actions between the two, and handling the flattening
that Sails performs in terms of case sensitivity for action identities
needed to be handled.

This PR re-examined the Sails 'router:bind' events and the Sails
'controller loading' process. It deals with both to produce a more
consistent mechanism with less tricky edge cases.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Refactor loading/parsing of controller files to utilise same mechanism
as Sails itself (results in better handling of edges case with case
sensitivity of filenames and related).

Refactor loading and parsing of controller JSDoc.

Refactor merging of controller file and JSDoc `swagger` elements.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Refactor association route aggregation to consider:
1. Blueprint prefix, REST prefix, and model including any pluralization
2. More complete grouping check including verb, model, and blueprint

Update api/controllers and api/models test data to include Sails
'model' and 'collection' associations (used for tests).
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

WIP commit (several back) excluded controllers+controllersJsDoc
from mergeComponents() and mergeTags(); re-integrate.
Add more test data including model associations, attribute validations,
updated `swagger` / `@swagger` sample documentation and options.
@danielsharvey
Copy link
Collaborator Author

Some thoughts on approach:

Documenting Model Schemas

We reference documenting schemas in relation to models (e.g. /User below) but the treatment is inconsistent, in that the description tag is used to populate the model OpenAPI.Schema, but the tags are actually documentation added to all blueprint actions (OpenApi.Operation) for the model.

I suggest:

  1. For @swagger: Use the /User documentation for OpenAPI.Schema properly with a convenience mechanism supporting tags for all blueprint actions as this is typically used to logically group operations in Swagger/OpenAPI renderers.
  2. For the swagger export: Make use of a new modelSchema element alongside the actions element. See below.
/**
 * @swagger
 *
 * /User:
 *   tags:
 *     - Tag Name
 * /findone:
 *   externalDocs:
 *     url: https://docs.com/here
 */
module.exports = {
  attributes: {
    uid: {
      type: 'string',
      example: '012345',
      description: 'A unique identifier',
    }
  },
  swagger: {
    actions: {
      create: { ... },
    },
    modelSchema: {
      externalDocs: { ... },
    },
    tags: [...]
    components: {...}
  }
};

Documenting Controllers

With reference to the convenience mechanism above, used to add a list of tags to all blueprint actions for a model, I propose a special action key named allActions which enables OpenAPI.Operation documentation to be added to all actions contained within the controller file. The obvious example being tags.

For example:

/**
 * @swagger
 *
 * /allActions:
 *   tags:
 *     - Auth
 * tags:
 *   - name: Auth
 *     description: Module description...
 */
module.exports = {
  ...
  swagger: {
    actions: {
      allActions: {
        tags: [ 'Auth' ],
      }
    }
  }
};

Let me know your thoughts @theoomoregbee.

Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Adjust some warnings from `sails.warn` to `sails.verbose`.

Correct shortcut blueprint route processing.

Add warning error messages for action documentation for actions which
do not exist.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Add warning error messages for action documentation for actions which
do not exist.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Tweak Typescript interfaces:
1. Adjust some mandatory OpenAPI elements to be optional as
   this hook auto-generates.
2. Remove unused interfaces as result of refactor.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Utilise new `swagger.modelSchema` element.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Incorporate transformation phase to merge parsed Swagger/JSDoc from
controller files to route actions.

Adjust initial creation of final Swagger/OpenAPI to improve ordering
of elements to show configured content first.
The `meta` attribute allows extensions to Sails Model attributes; add
`meta.swagger` to allow Swagger documentation to be added to the
OpenAPI.UpdatedSchema definition for the attribute.
Add support for excluding attributes/actions based upon respective
`swagger.exclude` attributes.
Part of adding additional ‘transformations’ phase to processing:
parse —> transform —> generate (better code structure and testing).

Utilise new `swagger.modelSchema` element.
@theoomoregbee
Copy link
Owner

@danielsharvey nice will go over this over the weekend 👍

@theoomoregbee theoomoregbee marked this pull request as ready for review May 30, 2020 19:20
@theoomoregbee theoomoregbee self-requested a review May 30, 2020 19:20
@theoomoregbee theoomoregbee changed the title WIP Refactor parsing and general refinements to configuration / generated Swagger Refactor parsing and general refinements to configuration / generated Swagger May 30, 2020
@@ -258,23 +291,27 @@ export const generatePaths = (routes: SwaggerRouteInfo[], templates: BlueprintAc
summary: subst(template.summary),
description: subst(template.description),
externalDocs: template.externalDocs || undefined,
tags: get(route, 'swagger.tags', []) as string[],
tags: route.swagger?.tags || route.model.swagger.modelSchema?.tags || route.model.swagger.actions?.allactions?.tags || [route.model.globalId],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

import { Tag } from "swagger-schema-official";
import { OpenApi } from "../types/openapi";
import path from "path";

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for moving this to transformations.ts

@@ -1,719 +1,2509 @@
{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried the generatedSwagger.json fixture on http://editor.swagger.io/ and got this

Screenshot 2020-05-30 at 17 53 05

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of the shortcut blueprints. line 628

/pet/create:
    get:
      summary: Create Pet *
      description: |-
        Create a new **Pet** record.

        (\*) Note that this is a [Sails blueprint shortcut route](https://sailsjs.com/documentation/concepts/blueprints/blueprint-routes#?shortcut-blueprint-routes) (recommended for **development-mode only**)
      externalDocs:
        url: 'https://sailsjs.com/documentation/reference/blueprint-api/create'
        description: 'See https://sailsjs.com/documentation/reference/blueprint-api/create'
      tags:
        - Pet
      parameters: []
      responses:
        '200':
          description: Responds with a JSON dictionary representing the newly created **Pet** instance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/pet'
        '404':
          description: Resource not found
        '500':
          description: Internal server error
      requestBody:
        description: JSON dictionary representing the Pet instance to create.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/pet'

the schema should have been under parameters as query param https://sailsjs.com/documentation/concepts/blueprints/blueprint-routes#?shortcut-blueprint-routes

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I uploaded to http://editor.swagger.io/ but without shortcuts. Fixing now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done; see new commits

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just checked, all good 👍 , but noticed the generateSchemaAsQueryParameters didn't work for one of the shortcut blueprint action
Screenshot 2020-06-01 at 20 19 47

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

},
} as unknown as Sails.Sails;

describe('Transformations', () => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Owner

@theoomoregbee theoomoregbee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct Typescript interfaces to use Record instead of Map - Map
implies implementation of the Map interface.

Update schema data type - 'file' not in OpenAPI 3.

Update Typescript interfaces for Parameter and Header to OpenAPI 3

Remove incorrect/unneeded EmptyObject references.
Correct shortcut blueprints; shortcuts have requestBody data supplied
as query parameters as a convenience during DEV.

Fix association foreign key parameter name in blueprint documentation;
was documented as `fk`, should be `childid`.

Adjust integer to be 64-bit; all numbers in JavaScript 64 bits.

Update test data.
OpenAPI 3 specifies the ***Any Type*** by the absence of the `type`
property in a schema; this may be achieved by setting a model
attribute's `meta.swagger.type` value to `null`.
This *should* be done by Sails bind but to be sure.
@danielsharvey
Copy link
Collaborator Author

@theoomoregbee Thanks for the review. I've addressed your concerns and a few more minor commits. See what you think.

Uploaded to https://redoc.ly/developer-portal yielding these issues
and fixes.

Refactor '$ref' checks using new common code.

Fix cross-generated-route data pollution by ensuring source swagger
data cloned.

Add underscore to path variable names, used to differentiate the PK
value used for paths from query variables. Specifically, differentiate
the PK value used for shortcut blueprint update routes, which allow for
PK update using query parameters. Some validators expect unique names
across all parameter types.

Sort tag name specified as part of Operation.

Update test data and test fixtures.
Copy link
Owner

@theoomoregbee theoomoregbee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can treat this as follow up if it won't take ur time:
#67 (comment)

@danielsharvey
Copy link
Collaborator Author

See changes correcting handling of blueprint actions overridden in controller. I'd put that test case in specifically but not picked up that the result was not correct :(

@theoomoregbee theoomoregbee merged commit a466521 into master Jun 4, 2020
@theoomoregbee theoomoregbee deleted the refactor-parsing branch June 4, 2020 22:18
@theoomoregbee
Copy link
Owner

🎉 This PR is included in version 3.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

auto generate tags for routes with model or just controllers
2 participants