From e45b800ad52709a478247bc4ef473cab3c6076d4 Mon Sep 17 00:00:00 2001 From: Danil Sotskov Date: Wed, 1 Oct 2025 18:01:20 +0300 Subject: [PATCH] feat: add spec download strategies --- .env_example | 5 + .gitignore | 3 +- bun.lockb | Bin 346771 -> 352323 bytes eslint.config.js | 1 + package.json | 3 +- scripts/create-spec.mjs | 49 ++ scripts/dow-spec.mjs | 62 +- scripts/strategies/baseStrategy.mjs | 4 + scripts/strategies/djangoStrategy.mjs | 88 +++ scripts/strategies/publicStrategy.mjs | 14 + spec/openapi.yaml | 845 -------------------------- 11 files changed, 197 insertions(+), 877 deletions(-) create mode 100644 .env_example create mode 100644 scripts/create-spec.mjs create mode 100644 scripts/strategies/baseStrategy.mjs create mode 100644 scripts/strategies/djangoStrategy.mjs create mode 100644 scripts/strategies/publicStrategy.mjs delete mode 100644 spec/openapi.yaml diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..5d6da56 --- /dev/null +++ b/.env_example @@ -0,0 +1,5 @@ +SPEC_URL= +SPEC_OUT= +SPEC_STRATEGY= +SPEC_USERNAME= +SPEC_PASSWORD= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1e332f7..a0da989 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ count.txt src/gen # Bun .bun-cache -.bun-version \ No newline at end of file +.bun-version +spec/ \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 13fe28e3f344edd495043db920d3b00f06c5b1e9..86e7bd543a179ff0352239b9a8a27647af5547a5 100755 GIT binary patch delta 47034 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 LZ(1YlTI~M=_4+^6 diff --git a/eslint.config.js b/eslint.config.js index 4ff07a3..d17eb0b 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -34,5 +34,6 @@ export default antfu({ "style/indent-binary-ops": "off", "style/indent": "off", "style/comma-dangle": "off", + "style/quote-props": "off", }, }); diff --git a/package.json b/package.json index 688de3d..f4e15c8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "postgenerate:kubb": "find src/gen/types -name '*.ts' -exec sed -i '' 's/\\[key: string\\]: string\\[\\] | null;/[key: string]: string[] | undefined;/g' {} \\;", "generate": "bun run generate:kubb && bun run generate:routes", "check:routes": "bun run generate:routes && git diff --exit-code src/routes/routes.gen.ts", - "download-spec": "bun scripts/dow-spec.mjs --url https://petstore3.swagger.io/api/v3/openapi.json --out ./spec/openapi.yaml" + "download-spec": "bun scripts/dow-spec.mjs --out ./spec/openapi.yaml" }, "dependencies": { "@hookform/resolvers": "^5.2.1", @@ -59,6 +59,7 @@ "@vitejs/plugin-react": "^4.3.4", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", + "cheerio": "^1.1.2", "eslint": "^9.34.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", diff --git a/scripts/create-spec.mjs b/scripts/create-spec.mjs new file mode 100644 index 0000000..b60a502 --- /dev/null +++ b/scripts/create-spec.mjs @@ -0,0 +1,49 @@ +import { Buffer } from "node:buffer"; +import fs from "node:fs/promises"; +import yaml from "js-yaml"; + +export class CreateSpec { + _url = ""; + _strategy = null; + _outPath = ""; + _outDir = ""; + + constructor({ url, strategy, outDir, outPath }) { + this._url = url; + this._outDir = outDir; + this._outPath = outPath; + this._strategy = strategy; + } + + async generate() { + const text = await this._strategy.download(this._url); + + await this._createFile(text); + } + + async _createFile(text) { + let yamlText; + const trimmed = text.trim(); + const looksLikeJson = trimmed.startsWith("{") || trimmed.startsWith("["); + + if (looksLikeJson) { + try { + const obj = JSON.parse(text); + yamlText = yaml.dump(obj, { noRefs: true }); + console.log("✅ JSON -> converted to YAML"); + } catch { + yamlText = text; + console.log("⚠️ JSON parse failed -> saving raw"); + } + } else { + yamlText = text; + console.log("✅ YAML -> saving as-is"); + } + + await fs.mkdir(this._outDir, { recursive: true }); + await fs.writeFile(this._outPath, yamlText, "utf8"); + console.log( + `💾 saved ${Buffer.byteLength(yamlText, "utf8")} bytes to ${this._outPath} (overwritten if existed)`, + ); + } +} diff --git a/scripts/dow-spec.mjs b/scripts/dow-spec.mjs index bf27cf2..892798f 100644 --- a/scripts/dow-spec.mjs +++ b/scripts/dow-spec.mjs @@ -7,12 +7,17 @@ * bun scripts/download-spec.mjs --url https://example.com/openapi.json --out ./spec/my.yaml */ -import { Buffer } from "node:buffer"; -import fs from "node:fs/promises"; import path from "node:path"; import process from "node:process"; -import yaml from "js-yaml"; import minimist from "minimist"; +import { CreateSpec } from "./create-spec.mjs"; +import { DjangoStrategy } from "./strategies/djangoStrategy.mjs"; +import { PublicStrategy } from "./strategies/publicStrategy.mjs"; + +const strategies = { + Public: PublicStrategy, + Django: DjangoStrategy, +}; const args = minimist(process.argv.slice(2), { string: ["url", "out"], @@ -20,6 +25,7 @@ const args = minimist(process.argv.slice(2), { }); const url = args.url || process.env.SPEC_URL; + if (!url) { console.error( "❌ SPEC URL not provided. Use --url, SPEC_URL env, or package.json specUrl", @@ -34,33 +40,29 @@ const outDir = path.dirname(outPath); console.log(`[spec] URL: ${url}`); console.log(`[spec] output: ${outPath}`); -// 1️⃣ Скачиваем spec -const res = await fetch(url); -if (!res.ok) - throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`); -const text = await res.text(); +const strategyArg = args.strategy || process.env.SPEC_STRATEGY; + +if (!strategyArg) { + console.error( + "❌ SPEC STRATEGY not provided. Use --strategy, or SPEC_STRATEGY env", + ); + process.exit(1); +} + +const strategy = new strategies[strategyArg](); -// 2️⃣ Конвертируем JSON -> YAML если нужно -let yamlText; -const trimmed = text.trim(); -const looksLikeJson = trimmed.startsWith("{") || trimmed.startsWith("["); -if (looksLikeJson) { - try { - const obj = JSON.parse(text); - yamlText = yaml.dump(obj, { noRefs: true }); - console.log("✅ JSON -> converted to YAML"); - } catch { - yamlText = text; - console.log("⚠️ JSON parse failed -> saving raw"); - } -} else { - yamlText = text; - console.log("✅ YAML -> saving as-is"); +if (!strategy) { + console.error("❌ SPEC STRATEGY is incorrect."); + process.exit(1); } -// 3️⃣ Создаём директорию (если нет) и перезаписываем файл -await fs.mkdir(outDir, { recursive: true }); -await fs.writeFile(outPath, yamlText, "utf8"); -console.log( - `💾 saved ${Buffer.byteLength(yamlText, "utf8")} bytes to ${outPath} (overwritten if existed)`, -); +console.log(`[spec] using strategy: ${strategyArg}`); + +const constructorSpec = new CreateSpec({ + url, + outDir, + outPath, + strategy, +}); + +await constructorSpec.generate(); diff --git a/scripts/strategies/baseStrategy.mjs b/scripts/strategies/baseStrategy.mjs new file mode 100644 index 0000000..2dd7e7e --- /dev/null +++ b/scripts/strategies/baseStrategy.mjs @@ -0,0 +1,4 @@ +export class BaseStrategy { + // url + async download(_) {} +} diff --git a/scripts/strategies/djangoStrategy.mjs b/scripts/strategies/djangoStrategy.mjs new file mode 100644 index 0000000..4ec8b16 --- /dev/null +++ b/scripts/strategies/djangoStrategy.mjs @@ -0,0 +1,88 @@ +import process from "node:process"; +import * as cheerio from "cheerio"; +import { BaseStrategy } from "./baseStrategy.mjs"; + +export class DjangoStrategy extends BaseStrategy { + _getSetCookie(response, names) { + const setCookie = response.headers.get("set-cookie"); + const cookies = []; + + for (let i = 0; i < names.length; i++) { + const name = names[i]; + let cookie = null; + + if (setCookie) { + const regex = new RegExp(`${name}=([^;]+)`); + const match = setCookie.match(regex); + if (match) cookie = match[1]; + } + + if (!cookie) { + console.error(`❌ Не удалось достать ${name} из Set-Cookie`); + process.exit(1); + } + + cookies.push(cookie); + } + + return cookies; + } + + async download(url) { + await super.download(url); + + const response = await fetch(url); + + if (!response.ok) { + throw new Error( + `Failed to fetch: ${response.status} ${response.statusText}`, + ); + } + + const html = await response.text(); + const $ = cheerio.load(html); + + const csrfmiddlewaretoken = $("input[name=csrfmiddlewaretoken]").val(); + const next = $("input[name=next]").val(); + const submit = $("input[name=submit]").val(); + + const csrftoken = this._getSetCookie(response, ["csrftoken"])[0]; + + const urlObj = new URL(response.url); + urlObj.search = ""; + + const urlWithoutSearch = urlObj.toString(); + const payload = new URLSearchParams({ + username: process.env.SPEC_USERNAME, + password: process.env.SPEC_PASSWORD, + next, + submit, + csrfmiddlewaretoken, + }); + + const loginResponse = await fetch(urlWithoutSearch, { + body: payload, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Cookie: `csrftoken=${csrftoken}`, + "X-CSRFToken": csrftoken, + Referer: response.url, + Origin: urlObj.origin, + }, + method: "POST", + redirect: "manual", + }); + + const sessionid = this._getSetCookie(loginResponse, ["sessionid"]); + const redirectURL = loginResponse.headers.get("location"); + const nextUrl = new URL(redirectURL, urlObj.origin); + + const docResponse = await fetch(nextUrl, { + headers: { + Cookie: `csrftoken=${csrftoken}; sessionid=${sessionid}`, + }, + }); + + return await docResponse.text(); + } +} diff --git a/scripts/strategies/publicStrategy.mjs b/scripts/strategies/publicStrategy.mjs new file mode 100644 index 0000000..2dbf2b6 --- /dev/null +++ b/scripts/strategies/publicStrategy.mjs @@ -0,0 +1,14 @@ +import { BaseStrategy } from "./baseStrategy.mjs"; + +export class PublicStrategy extends BaseStrategy { + async download(url) { + await super.download(url); + + const res = await fetch(url); + + if (!res.ok) + throw new Error(`Failed to fetch: ${res.status} ${res.statusText}`); + + return await res.text(); + } +} diff --git a/spec/openapi.yaml b/spec/openapi.yaml deleted file mode 100644 index afe5401..0000000 --- a/spec/openapi.yaml +++ /dev/null @@ -1,845 +0,0 @@ -openapi: 3.0.4 -info: - title: Swagger Petstore - OpenAPI 3.0 - description: >- - This is a sample Pet Store Server based on the OpenAPI 3.0 specification. - You can find out more about - - Swagger at [https://swagger.io](https://swagger.io). In the third iteration - of the pet store, we've switched to the design first approach! - - You can now help us improve the API whether it's by making changes to the - definition itself or to the code. - - That way, with time, we can improve the API in general, and expose some of - the new features in OAS3. - - - Some useful links: - - - [The Pet Store - repository](https://github.com/swagger-api/swagger-petstore) - - - [The source API definition for the Pet - Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) - termsOfService: https://swagger.io/terms/ - contact: - email: apiteam@swagger.io - license: - name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0.html - version: 1.0.27 -externalDocs: - description: Find out more about Swagger - url: https://swagger.io -servers: - - url: /api/v3 -tags: - - name: pet - description: Everything about your Pets - externalDocs: - description: Find out more - url: https://swagger.io - - name: store - description: Access to Petstore orders - externalDocs: - description: Find out more about our store - url: https://swagger.io - - name: user - description: Operations about user -paths: - /pet: - put: - tags: - - pet - summary: Update an existing pet. - description: Update an existing pet by Id. - operationId: updatePet - requestBody: - description: Update an existent pet in the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - required: true - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - '422': - description: Validation exception - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - post: - tags: - - pet - summary: Add a new pet to the store. - description: Add a new pet to the store. - operationId: addPet - requestBody: - description: Create a new pet in the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Pet' - required: true - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid input - '422': - description: Validation exception - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - /pet/findByStatus: - get: - tags: - - pet - summary: Finds Pets by status. - description: Multiple status values can be provided with comma separated strings. - operationId: findPetsByStatus - parameters: - - name: status - in: query - description: Status values that need to be considered for filter - required: true - explode: true - schema: - type: string - default: available - enum: - - available - - pending - - sold - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid status value - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - /pet/findByTags: - get: - tags: - - pet - summary: Finds Pets by tags. - description: >- - Multiple tags can be provided with comma separated strings. Use tag1, - tag2, tag3 for testing. - operationId: findPetsByTags - parameters: - - name: tags - in: query - description: Tags to filter by - required: true - explode: true - schema: - type: array - items: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - type: array - items: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid tag value - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - /pet/{petId}: - get: - tags: - - pet - summary: Find pet by ID. - description: Returns a single pet. - operationId: getPetById - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - default: - description: Unexpected error - security: - - api_key: [] - - petstore_auth: - - write:pets - - read:pets - post: - tags: - - pet - summary: Updates a pet in the store with form data. - description: Updates a pet resource based on the form data. - operationId: updatePetWithForm - parameters: - - name: petId - in: path - description: ID of pet that needs to be updated - required: true - schema: - type: integer - format: int64 - - name: name - in: query - description: Name of pet that needs to be updated - schema: - type: string - - name: status - in: query - description: Status of pet that needs to be updated - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - '400': - description: Invalid input - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - delete: - tags: - - pet - summary: Deletes a pet. - description: Delete a pet. - operationId: deletePet - parameters: - - name: api_key - in: header - description: '' - required: false - schema: - type: string - - name: petId - in: path - description: Pet id to delete - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: Pet deleted - '400': - description: Invalid pet value - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - /pet/{petId}/uploadImage: - post: - tags: - - pet - summary: Uploads an image. - description: Upload image of the pet. - operationId: uploadFile - parameters: - - name: petId - in: path - description: ID of pet to update - required: true - schema: - type: integer - format: int64 - - name: additionalMetadata - in: query - description: Additional Metadata - required: false - schema: - type: string - requestBody: - content: - application/octet-stream: - schema: - type: string - format: binary - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - '400': - description: No file uploaded - '404': - description: Pet not found - default: - description: Unexpected error - security: - - petstore_auth: - - write:pets - - read:pets - /store/inventory: - get: - tags: - - store - summary: Returns pet inventories by status. - description: Returns a map of status codes to quantities. - operationId: getInventory - responses: - '200': - description: successful operation - content: - application/json: - schema: - type: object - additionalProperties: - type: integer - format: int32 - default: - description: Unexpected error - security: - - api_key: [] - /store/order: - post: - tags: - - store - summary: Place an order for a pet. - description: Place a new order in the store. - operationId: placeOrder - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - application/xml: - schema: - $ref: '#/components/schemas/Order' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/Order' - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid input - '422': - description: Validation exception - default: - description: Unexpected error - /store/order/{orderId}: - get: - tags: - - store - summary: Find purchase order by ID. - description: >- - For valid response try integer IDs with value <= 5 or > 10. Other values - will generate exceptions. - operationId: getOrderById - parameters: - - name: orderId - in: path - description: ID of order that needs to be fetched - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - application/xml: - schema: - $ref: '#/components/schemas/Order' - '400': - description: Invalid ID supplied - '404': - description: Order not found - default: - description: Unexpected error - delete: - tags: - - store - summary: Delete purchase order by identifier. - description: >- - For valid response try integer IDs with value < 1000. Anything above - 1000 or non-integers will generate API errors. - operationId: deleteOrder - parameters: - - name: orderId - in: path - description: ID of the order that needs to be deleted - required: true - schema: - type: integer - format: int64 - responses: - '200': - description: order deleted - '400': - description: Invalid ID supplied - '404': - description: Order not found - default: - description: Unexpected error - /user: - post: - tags: - - user - summary: Create user. - description: This can only be done by the logged in user. - operationId: createUser - requestBody: - description: Created user object - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - default: - description: Unexpected error - /user/createWithList: - post: - tags: - - user - summary: Creates list of users with given input array. - description: Creates list of users with given input array. - operationId: createUsersWithListInput - requestBody: - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - default: - description: Unexpected error - /user/login: - get: - tags: - - user - summary: Logs user into the system. - description: Log into the system. - operationId: loginUser - parameters: - - name: username - in: query - description: The user name for login - required: false - schema: - type: string - - name: password - in: query - description: The password for login in clear text - required: false - schema: - type: string - responses: - '200': - description: successful operation - headers: - X-Rate-Limit: - description: calls per hour allowed by the user - schema: - type: integer - format: int32 - X-Expires-After: - description: date in UTC when token expires - schema: - type: string - format: date-time - content: - application/xml: - schema: - type: string - application/json: - schema: - type: string - '400': - description: Invalid username/password supplied - default: - description: Unexpected error - /user/logout: - get: - tags: - - user - summary: Logs out current logged in user session. - description: Log user out of the system. - operationId: logoutUser - parameters: [] - responses: - '200': - description: successful operation - default: - description: Unexpected error - /user/{username}: - get: - tags: - - user - summary: Get user by user name. - description: Get user detail based on username. - operationId: getUserByName - parameters: - - name: username - in: path - description: The name that needs to be fetched. Use user1 for testing - required: true - schema: - type: string - responses: - '200': - description: successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - '400': - description: Invalid username supplied - '404': - description: User not found - default: - description: Unexpected error - put: - tags: - - user - summary: Update user resource. - description: This can only be done by the logged in user. - operationId: updateUser - parameters: - - name: username - in: path - description: name that need to be deleted - required: true - schema: - type: string - requestBody: - description: Update an existent user in the store - content: - application/json: - schema: - $ref: '#/components/schemas/User' - application/xml: - schema: - $ref: '#/components/schemas/User' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/User' - responses: - '200': - description: successful operation - '400': - description: bad request - '404': - description: user not found - default: - description: Unexpected error - delete: - tags: - - user - summary: Delete user resource. - description: This can only be done by the logged in user. - operationId: deleteUser - parameters: - - name: username - in: path - description: The name that needs to be deleted - required: true - schema: - type: string - responses: - '200': - description: User deleted - '400': - description: Invalid username supplied - '404': - description: User not found - default: - description: Unexpected error -components: - schemas: - Order: - type: object - properties: - id: - type: integer - format: int64 - example: 10 - petId: - type: integer - format: int64 - example: 198772 - quantity: - type: integer - format: int32 - example: 7 - shipDate: - type: string - format: date-time - status: - type: string - description: Order Status - example: approved - enum: - - placed - - approved - - delivered - complete: - type: boolean - xml: - name: order - Category: - type: object - properties: - id: - type: integer - format: int64 - example: 1 - name: - type: string - example: Dogs - xml: - name: category - User: - type: object - properties: - id: - type: integer - format: int64 - example: 10 - username: - type: string - example: theUser - firstName: - type: string - example: John - lastName: - type: string - example: James - email: - type: string - example: john@email.com - password: - type: string - example: '12345' - phone: - type: string - example: '12345' - userStatus: - type: integer - description: User Status - format: int32 - example: 1 - xml: - name: user - Tag: - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: tag - Pet: - required: - - name - - photoUrls - type: object - properties: - id: - type: integer - format: int64 - example: 10 - name: - type: string - example: doggie - category: - $ref: '#/components/schemas/Category' - photoUrls: - type: array - xml: - wrapped: true - items: - type: string - xml: - name: photoUrl - tags: - type: array - xml: - wrapped: true - items: - $ref: '#/components/schemas/Tag' - status: - type: string - description: pet status in the store - enum: - - available - - pending - - sold - xml: - name: pet - ApiResponse: - type: object - properties: - code: - type: integer - format: int32 - type: - type: string - message: - type: string - xml: - name: '##default' - requestBodies: - Pet: - description: Pet object that needs to be added to the store - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' - application/xml: - schema: - $ref: '#/components/schemas/Pet' - UserArray: - description: List of user object - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - securitySchemes: - petstore_auth: - type: oauth2 - flows: - implicit: - authorizationUrl: https://petstore3.swagger.io/oauth/authorize - scopes: - write:pets: modify pets in your account - read:pets: read your pets - api_key: - type: apiKey - name: api_key - in: header