Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs-util: support generating OAS in docblock generator (#6338)
## What This PR adds support for generating OAS in the docblock generator tool. ## How As OAS are generated in a different manner/location than regular TSDocs, it requires a new type of generator within the tool. As such, the existing docblock generator now only handles files that aren't under the `packages/medusa/src/api` and `packages/medusa/src/api-v2` directories. The new generator handles files under these directories. However, it only considers a node to be an API route if it's a function having two parameters of types `MedusaRequest` and `MedusaResponse` respectively. So, only new API Routes are considered. The new generator runs the same way as the existing docblock generator with the same method. The generators will detect whether they can run on the file or not and the docblocks/oas are generated based on that. I've also added a `--type` option to the CLI commands of the docblock generator tool to further filter and choose which generator to use. When the OAS generator finds an API route, it will generate its OAS under the `docs-util/oas-output/operations` directory in a TypeScript file. I chose to generate in TS files rather than YAML files to maintain the functionality of `medusa-oas` without major changes. Schemas detected in the OAS operation, such as the request and response schemas, are generated as OAS schemas under the `docs-util/oas-output/schemas` directory and referenced in operations and other resources. The OAS generator also handles updating OAS. When you run the same command on a file/directory and an API route already has OAS associated with it, its information and associated schemas are updated instead of generating new schemas/operations. However, summaries and descriptions aren't updated unless they're not available or their values are the default value SUMMARY. ## API Route Handling ### Request and Response Types The tool extracts the type of request/response schemas from the type arguments passed to the `MedusaRequest` and `MedusaResponse` respectively. For example: ```ts export const POST = async ( req: MedusaRequest<{ id: string }>, res: MedusaResponse<ResponseType> ) => { // ... } ``` If these types aren't provided, the request/response is considered empty. ### Path Parameters Path parameters are extracted from the file's path name. For example, for `packages/medusa/src/api-v2/admin/campaigns/[id]/route.ts` the `id` path parameter is extracted. ### Query Parameters The tool extracts the query parameters of an API route based on the type of `request.validatedQuery`. Once we narrow down how we're typing query parameters, we can revisit this implementation. ## Changes to Medusa Oas CLI I added a `--v2` option to the Medusa OAS CLI to support loading OAS from `docs-util/oas-output` directory rather than the `medusa` package. This will output the OAS in `www/apps/api-reference/specs`, wiping out old OAS. This is only helpful for testing purposes to check how the new OAS looks like in the API reference. It also allows us to slowly start adapting the new OAS. ## Other Notes and Changes - I've added a GitHub action that creates a PR for generated OAS when Version Packages is merged (similar to regular TSDocs). However, this will only generate the OAS in the `docs-util/oas-output` directory and will not affect the existing OAS in the API reference. Once we're ready to include it those OAS, we can talk about next steps. - I've moved the base YAML from the `medusa` package to the `docs-util/oas-output/base` directory and changed the `medusa-oas` tool to load them from there. - I added a `clean:oas` command to the docblock generator CLI tool that removes unused OAS operations, schemas, and tags from `docs-util/oas-output`. The tool also supports updating OAS operations and their associated schemas. However, I didn't add a specific mechanism to update schemas on their own as that's a bit tricky and would require the help of typedoc. I believe with the process of running the tool on the `api-v2` directory whenever there's a new release should be enough to update associated schemas, but if we find that not enough, we can revisit updating schemas individually. - Because of the `clean:oas` command which makes changes to tags (removing the existing ones, more details on this one later), I've added new base YAML under `docs-util/oas-output/base-v2`. This is used by the tool when generating/cleaning OAS, and the Medusa OAS CLI when the `--v2` option is used. ## Testing ### Prerequisites To test with request/response types, I recommend minimally modifying `packages/medusa/src/types/routing.ts` to allow type arguments of `MedusaRequest` and `MedusaResponse`: ```ts import type { NextFunction, Request, Response } from "express" import type { Customer, User } from "../models" import type { MedusaContainer } from "./global" export interface MedusaRequest<T = unknown> extends Request { user?: (User | Customer) & { customer_id?: string; userId?: string } scope: MedusaContainer } export type MedusaResponse<T = unknown> = Response export type MedusaNextFunction = NextFunction export type MedusaRequestHandler = ( req: MedusaRequest, res: MedusaResponse, next: MedusaNextFunction ) => Promise<void> | void ``` You can then add type arguments to the routes in `packages/medusa/src/api-v2/admin/campaigns/[id]/route.ts`. For example: ```ts import { deleteCampaignsWorkflow, updateCampaignsWorkflow, } from "@medusajs/core-flows" import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { CampaignDTO, IPromotionModuleService } from "@medusajs/types" import { MedusaRequest, MedusaResponse } from "../../../../types/routing" interface ResponseType { campaign: CampaignDTO } export const GET = async ( req: MedusaRequest, res: MedusaResponse<ResponseType> ) => { const promotionModuleService: IPromotionModuleService = req.scope.resolve( ModuleRegistrationName.PROMOTION ) const campaign = await promotionModuleService.retrieveCampaign( req.params.id, { select: req.retrieveConfig.select, relations: req.retrieveConfig.relations, } ) res.status(200).json({ campaign }) } export const POST = async ( req: MedusaRequest<{ id: string }>, res: MedusaResponse<ResponseType> ) => { const updateCampaigns = updateCampaignsWorkflow(req.scope) const campaignsData = [ { id: req.params.id, ...(req.validatedBody || {}), }, ] const { result, errors } = await updateCampaigns.run({ input: { campaignsData }, throwOnError: false, }) if (Array.isArray(errors) && errors[0]) { throw errors[0].error } res.status(200).json({ campaign: result[0] }) } export const DELETE = async ( req: MedusaRequest, res: MedusaResponse<{ id: string object: string deleted: boolean }> ) => { const id = req.params.id const manager = req.scope.resolve("manager") const deleteCampaigns = deleteCampaignsWorkflow(req.scope) const { errors } = await deleteCampaigns.run({ input: { ids: [id] }, context: { manager }, throwOnError: false, }) if (Array.isArray(errors) && errors[0]) { throw errors[0].error } res.status(200).json({ id, object: "campaign", deleted: true, }) } ``` ### Generate OAS - Install dependencies in the `docs-util` directory - Run the following command in the `docs-util/packages/docblock-generator` directory: ```bash yarn dev run "../../../packages/medusa/src/api-v2/admin/campaigns/[id]/route.ts" ``` This will generate the OAS operation and schemas and necessary and update the base YAML to include the new tags. ### Generate OAS with Examples By default, the tool will only generate cURL examples for OAS operations. To generate templated JS Client and (placeholder) Medusa React examples, add the `--generate-examples` option to the command: ```bash yarn dev run "../../../packages/medusa/src/api-v2/admin/campaigns/[id]/route.ts" --generate-examples ``` > Note: the command will update the existing OAS you generated in the previous test. ### Testing Updates To test updating OAS, you can try updating request/response types, then running the command, and the associated OAS/schemas will be updated. ### Clean OAS The `clean:oas` command will remove any unused operation, tags, or schemas. To test it out you can try: - Remove an API Route => this removes its associated operation and schemas (if not referenced anywhere else). - Remove all references to a schema => this removes the schema. - Remove all operations in `docs-util/oas-output/operations` associated with a tag => this removes the tag from the base YAML. ```bash yarn dev clean:oas ``` > Note: when running this command, existing tags in the base YAML (such as Products) will be removed since there are no operations using it. As it's running on the base YAML under `base-v2`, this doesn't affect base YAML used for the API reference. ### Medusa Oas CLI - Install and build dependencies in the root of the monorepo - Run the following command to generate reference OAS for v2 API Routes (must have generated OAS previously using the docblock generator tool): ```bash yarn openapi:generate --v2 ``` - This wipes out existing OAS in `www/apps/api-reference/specs` and replaces them with the new ones. At this point, you can view the new API routes in the API reference by running the `yarn dev` command in `www/apps/api-reference` (although not necessary for testing here). - Run the command again without the `--v2` option: ```bash yarn openapi:generate ``` The specs in `www/apps/api-reference/specs` are reverted back to the old routes.
- Loading branch information