From f6677065d0016382688bc3054717f90d15882c4a Mon Sep 17 00:00:00 2001 From: J3m5 <5523410+J3m5@users.noreply.github.com> Date: Thu, 3 Jul 2025 18:05:23 +0200 Subject: [PATCH 1/5] chore(readme): improve, extend content, fix links, format, add sections... --- README.md | 351 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 312 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 6ea964c..aa4008f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,63 @@ -# API Doc Parser - -[![GitHub Actions](https://github.com/api-platform/api-doc-parser/workflows/CI/badge.svg?branch=main)](https://github.com/api-platform/api-doc-parser/actions?query=workflow%3ACI+branch%3Amain) -[![npm version](https://badge.fury.io/js/%40api-platform%2Fapi-doc-parser.svg)](https://badge.fury.io/js/%40api-platform%2Fapi-doc-parser) - -`api-doc-parser` is a standalone TypeScript library to parse [Hydra](http://hydra-cg.com), [Swagger](https://swagger.io/specification/v2/), [OpenAPI](https://github.com/OAI/OpenAPI-Specification#the-openapi-specification) and [GraphQL](https://graphql.org/) documentations -and transform them in an intermediate representation. -This data structure can then be used for various tasks such as creating smart API clients, -scaffolding code or building administration interfaces. - -It plays well with the [API Platform](https://api-platform.com) framework. - -## Install +

+
+API Doc Parser +

+ +

+ +Effortlessly turn Hydra, Swagger/OpenAPI, and GraphQL specs into actionable data for your tools and apps. + +

+ +

+ + CI + + + GitHub License + + + npm bundle size + + + npm version + + + NPM Downloads + +

+ +

+ Installation • + Usage • + Type definitions • + Contributing • + Credits • + License +

+ +--- + +
+

+ api-doc-parser is a standalone TypeScript library that parses + Hydra, + Swagger, + OpenAPI, + and GraphQL documentation into a unified, intermediate representation.
+ This normalized structure enables smart API clients, code generators, admin interfaces, and more.
+ It integrates seamlessly with the API Platform framework. +

+ +## ✨ Key Features + +- **Unified output** – one normalized `Api` object covering resources, fields, operations, parameters, and relations +- **TypeScript-first** – strict typings for every parsed element +- **Embedded & referenced resources** resolved automatically +- **Framework integration** – easily integrates with the API Platform ecosystem +- **Supports all major API formats** – Hydra, Swagger/OpenAPI v2, OpenAPI v3, and GraphQL + +## 📦 Installation With [Yarn](https://yarnpkg.com/): @@ -24,11 +71,11 @@ Using [Pnpm](https://pnpm.io/): pnpm add @api-platform/api-doc-parser -If you plan to use the library with Node, you also need a polyfill for the `fetch` function: +Using [Bun](https://bun.sh/): - yarn add isomorphic-fetch + bun add @api-platform/api-doc-parser -## Usage +## 🚀 Usage **Hydra** @@ -56,7 +103,7 @@ parseSwaggerDocumentation("https://demo.api-platform.com/docs.json").then( import { parseOpenApi3Documentation } from "@api-platform/api-doc-parser"; parseOpenApi3Documentation( - "https://demo.api-platform.com/docs.json?spec_version=3", + "https://demo.api-platform.com/docs.jsonopenapi?spec_version=3.0.0", ).then(({ api }) => console.log(api)); ``` @@ -70,37 +117,263 @@ parseGraphQl("https://demo.api-platform.com/graphql").then(({ api }) => ); ``` -## OpenAPI Support +## TypeScript Type definitions + +Each parse function returns a Promise that resolves to an object containing the normalized API structure, the raw documentation, and the HTTP status code: + +#### OpenAPI 3 + +```typescript +function parseOpenApi3Documentation( + entrypointUrl: string, + options?: RequestInitExtended, +): Promise<{ + api: Api; + response: OpenAPIV3.Document; + status: number; +}>; +``` + +#### Swagger + +```typescript +function parseSwaggerDocumentation(entrypointUrl: string): Promise<{ + api: Api; + response: OpenAPIV2.Document; + status: number; +}>; +``` + +#### Hydra + +```typescript +function parseHydraDocumentation( + entrypointUrl: string, + options?: RequestInitExtended, +): Promise<{ + api: Api; + response: Response; + status: number; +}>; +``` + +#### GraphQL + +```typescript +function parseGraphQl( + entrypointUrl: string, + options?: RequestInit, +): Promise<{ + api: Api; + response: Response; +}>; +``` + +### Api + +Represents the root of the parsed API, containing the entrypoint URL, an optional title, and a list of resources. + +```typescript +interface Api { + entrypoint: string; + title?: string; + resources?: Resource[]; +} +``` + +### Resource + +Describes an API resource (such as an entity or collection), including its fields, operations, and metadata. + +```typescript +interface Resource { + name: string | null; + url: string | null; + id?: string | null; + title?: string | null; + description?: string | null; + deprecated?: boolean | null; + fields?: Field[] | null; + readableFields?: Field[] | null; + writableFields?: Field[] | null; + parameters?: Parameter[] | null; + getParameters?: () => Promise | null; + operations?: Operation[] | null; +} +``` + +### Field + +Represents a property of a resource, including its type, constraints, and metadata. + +```typescript +interface Field { + name: string | null; + id?: string | null; + range?: string | null; + type?: FieldType | null; + arrayType?: FieldType | null; + enum?: { [key: string | number]: string | number } | null; + reference?: string | Resource | null; + embedded?: Resource | null; + required?: boolean | null; + nullable?: boolean | null; + description?: string | null; + maxCardinality?: number | null; + deprecated?: boolean | null; +} +``` + +### Parameter + +Represents a query parameter for a collection/list operation, such as a filter or pagination variable. + +```typescript +interface Parameter { + variable: string; + range: string | null; + required: boolean; + description: string; + deprecated?: boolean; +} +``` + +### FieldType + +Enumerates the possible types for a field, such as string, integer, date, etc. + +```typescript +type FieldType = + | "string" + | "integer" + | "negativeInteger" + | "nonNegativeInteger" + | "positiveInteger" + | "nonPositiveInteger" + | "number" + | "decimal" + | "double" + | "float" + | "boolean" + | "date" + | "dateTime" + | "duration" + | "time" + | "byte" + | "binary" + | "hexBinary" + | "base64Binary" + | "array" + | "object" + | "email" + | "url" + | "uuid" + | "password" + | string; +``` -In order to support OpenAPI, the library makes some assumptions about how the documentation relates to a corresponding ressource: +### Operation + +Represents an operation (such as GET, POST, PUT, PATCH, DELETE) that can be performed on a resource. + +```typescript +interface Operation { + name: string | null; + type: "show" | "edit" | "delete" | "list" | "create" | null; + method?: string | null; + expects?: any | null; + returns?: string | null; + types?: string[] | null; + deprecated?: boolean | null; +} +``` -- The path to get (`GET`) or edit (`PUT`) one resource looks like `/books/{id}` (regular expression used: `^[^{}]+/{[^{}]+}/?$`). - Note that `books` may be a singular noun (`book`). - If there is no path like this, the library skips the resource. -- The corresponding path schema is retrieved for `get` either in the [`response` / `200` / `content` / `application/json`] path section or in the `components` section of the documentation. - If retrieved from the `components` section, the component name needs to look like `Book` (singular noun). - For `put`, the schema is only retrieved in the [`requestBody` / `content` / `application/json`] path section. - If no schema is found, the resource is skipped. -- If there are two schemas (one for `get` and one for `put`), resource fields are merged. -- The library looks for a creation (`POST`) and list (`GET`) path. They need to look like `/books` (plural noun). -- The deletion (`DELETE`) path needs to be inside the get / edit path. -- In order to reference the resources between themselves (embeddeds or relations), the library guesses embeddeds or references from property names. - For instance if a book schema has a `reviews` property, the library tries to find a `Review` resource. - If there is, a relation or an embedded between `Book` and `Review` resources is made for the `reviews` field. - The property name can also be like `review_id`, `reviewId`, `review_ids` or `reviewIds` for references. -- Parameters are only retrieved in the list path. +## 📖 OpenAPI Support -## Support for other formats (JSON:API...) +`api-doc-parser` applies a predictable set of rules when interpreting an OpenAPI document. +If a rule is not met, the resource concerned is silently skipped. +| Rule | Details | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Single-item path pattern** | A `GET` (read) or **`PUT`/`PATCH`** (update) endpoint **must** match:
`/books/{id}` (regex `^[^{}]+/{[^{}]+}/?$`).
`books` may be singular (`/book/{id}`). | +| **Schema discovery** | **GET** → first searches `responses → 200 → content → application/json`; if missing, falls back to `components` (component name must be singular, e.g. `Book`).
**PUT/PATCH** → only `requestBody → content → application/json` is considered.
If both GET & PUT/PATCH schemas exist, their fields are **merged**. | +| **Collection paths** | A create (`POST`) or list (`GET`) endpoint **must** be plural:
`/books`. | +| **Deletion path** | `DELETE` must live under the single-item GET path (`/books/{id}`). | +| **Relations & Embeddeds** | Links between resources are inferred from property names and their JSON schema:
• **Plural object/array properties** (e.g. `reviews`, `authors`) become **embedded** resources when their item schema matches an existing resource (`Review`, `Author`).
• **ID-like properties** (e.g. `review_id`, `reviewId`, `review_ids`, `reviewIds`, `authorId`) are treated as **references** to that resource.
• Matching algorithm: `camelize` → strip trailing `Id`/`Ids` → `classify` (singular PascalCase) → exact compare with resource titles. This effectively handles both plural and ID variants, regardless of original casing.
• As a result, fields such as **`reviews`** (object/array) and **`review_ids`** (scalar/array of IDs) each point to the **same** `Review` resource, one flagged _embedded_, the other _reference_. | +| **Parameter extraction** | Parameters are read **only** from the list path (`/books`). | + +## 🧩 Support for other formats (JSON:API, AsyncAPI...) API Doc Parser is designed to parse any API documentation format and convert it in the same intermediate representation. If you develop a parser for another format, please [open a Pull Request](https://github.com/api-platform/api-doc-parser/pulls) to include it in the library. -## Run tests +## 🤝 Contributing + +Contributions are welcome! To contribute: + +1. **Read our [Code of Conduct](https://github.com/api-platform/api-doc-parser?tab=coc-ov-file#contributor-code-of-conduct).** + +2. **Fork the repository and create a feature branch.** + +3. **Install dependencies** + + ```bash + pnpm install + ``` - pnpm test - pnpm lint +4. **Adhere to the code style** -## Credits + ```bash + pnpm lint:fix + ``` + + ```bash + pnpm format + ``` + +5. **Run tests** + + ```bash + pnpm test + ``` + +6. **Ensure type correctness** + + ```bash + pnpm typecheck + ``` + +7. **Submit a pull request with a clear description of your changes.** + +## 👥 Contributors + + + + + +## 🌟 Star History + + + + + + Star History Chart + + + +## 🎉 Credits Created by [Kévin Dunglas](https://dunglas.fr). Sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop). + +## 🔒 License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. From 658da99c49e7619513b2d5cc0061f11fba9b4b19 Mon Sep 17 00:00:00 2001 From: J3m5 <5523410+J3m5@users.noreply.github.com> Date: Fri, 4 Jul 2025 10:01:39 +0200 Subject: [PATCH 2/5] chore(readme): remove HTML and quick access links except for star history chart --- README.md | 67 +++++++++++++------------------------------------------ 1 file changed, 15 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index aa4008f..3b9f307 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,18 @@ -

-
-API Doc Parser -

- -

- -Effortlessly turn Hydra, Swagger/OpenAPI, and GraphQL specs into actionable data for your tools and apps. - -

- -

- - CI - - - GitHub License - - - npm bundle size - - - npm version - - - NPM Downloads - -

- -

- Installation • - Usage • - Type definitions • - Contributing • - Credits • - License -

+# API Doc Parser + +**Effortlessly turn Hydra, Swagger/OpenAPI, and GraphQL specs into actionable data for your tools and apps.** + +[![CI](https://github.com/api-platform/api-doc-parser/actions/workflows/ci.yml/badge.svg)](https://github.com/api-platform/api-doc-parser/actions/workflows/ci.yml) +[![GitHub License](https://img.shields.io/github/license/api-platform/api-doc-parser)](https://github.com/api-platform/api-doc-parser/blob/main/LICENSE) +[![npm bundle size](https://img.shields.io/bundlephobia/minzip/@api-platform/api-doc-parser)](https://bundlephobia.com/package/@api-platform/api-doc-parser) +[![npm version](https://badge.fury.io/js/%40api-platform%2Fapi-doc-parser.svg)](https://badge.fury.io/js/%40api-platform%2Fapi-doc-parser) +[![NPM Downloads](https://img.shields.io/npm/dw/%40api-platform%2Fapi-doc-parser)](https://img.shields.io/npm/dw/%40api-platform%2Fapi-doc-parser) --- -
-

- api-doc-parser is a standalone TypeScript library that parses - Hydra, - Swagger, - OpenAPI, - and GraphQL documentation into a unified, intermediate representation.
- This normalized structure enables smart API clients, code generators, admin interfaces, and more.
- It integrates seamlessly with the API Platform framework. -

+**`api-doc-parser` is a standalone TypeScript library that parses [Hydra](https://www.hydra-cg.com/), [Swagger](https://swagger.io/specification/v2/), [OpenAPI](https://github.com/OAI/OpenAPI-Specification#the-openapi-specification), and [GraphQL](https://graphql.org/) documentation into a unified, intermediate representation.** +This normalized structure enables smart API clients, code generators, admin interfaces, and more. +It integrates seamlessly with the [API Platform](https://api-platform.com/) framework. ## ✨ Key Features @@ -117,7 +82,7 @@ parseGraphQl("https://demo.api-platform.com/graphql").then(({ api }) => ); ``` -## TypeScript Type definitions +## ![TypeScript](https://api.iconify.design/vscode-icons:file-type-typescript-official.svg?color=%23888888&wdith=26&height=26) Type definitions Each parse function returns a Promise that resolves to an object containing the normalized API structure, the raw documentation, and the HTTP status code: @@ -298,7 +263,7 @@ If a rule is not met, the resource concerned is silently skipped. | **Schema discovery** | **GET** → first searches `responses → 200 → content → application/json`; if missing, falls back to `components` (component name must be singular, e.g. `Book`).
**PUT/PATCH** → only `requestBody → content → application/json` is considered.
If both GET & PUT/PATCH schemas exist, their fields are **merged**. | | **Collection paths** | A create (`POST`) or list (`GET`) endpoint **must** be plural:
`/books`. | | **Deletion path** | `DELETE` must live under the single-item GET path (`/books/{id}`). | -| **Relations & Embeddeds** | Links between resources are inferred from property names and their JSON schema:
• **Plural object/array properties** (e.g. `reviews`, `authors`) become **embedded** resources when their item schema matches an existing resource (`Review`, `Author`).
• **ID-like properties** (e.g. `review_id`, `reviewId`, `review_ids`, `reviewIds`, `authorId`) are treated as **references** to that resource.
• Matching algorithm: `camelize` → strip trailing `Id`/`Ids` → `classify` (singular PascalCase) → exact compare with resource titles. This effectively handles both plural and ID variants, regardless of original casing.
• As a result, fields such as **`reviews`** (object/array) and **`review_ids`** (scalar/array of IDs) each point to the **same** `Review` resource, one flagged _embedded_, the other _reference_. | +| **Relations & Embeddeds** | Links between resources are inferred from property names and their JSON schema:
• **Plural object/array properties** (e.g. `reviews`, `authors`) become **embedded** resources when their item schema matches an existing resource (`Review`, `Author`).
• **ID-like properties** (e.g. `review_id`, `reviewId`, `review_ids`, `reviewIds`, `authorId`) are treated as **references** to that resource.
• As a result, fields such as **`reviews`** (object/array) and **`review_ids`** (scalar/array of IDs) each point to the **same** `Review` resource, one flagged _embedded_, the other _reference_. | | **Parameter extraction** | Parameters are read **only** from the list path (`/books`). | ## 🧩 Support for other formats (JSON:API, AsyncAPI...) @@ -347,9 +312,7 @@ Contributions are welcome! To contribute: ## 👥 Contributors - - - +[![Contributors](https://contrib.rocks/image?repo=api-platform/api-doc-parser)](https://github.com/api-platform/api-doc-parser/graphs/contributors) ## 🌟 Star History From 498ed8612324dd5f90abda544d6cfeb27dcfba0e Mon Sep 17 00:00:00 2001 From: J3m5 <5523410+J3m5@users.noreply.github.com> Date: Fri, 4 Jul 2025 15:32:51 +0200 Subject: [PATCH 3/5] chore(readme): add custom logo --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 3b9f307..39c7101 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +

+API doc parser +

+ # API Doc Parser **Effortlessly turn Hydra, Swagger/OpenAPI, and GraphQL specs into actionable data for your tools and apps.** From 9153a606689d620e22d22725fca48ae8a9e01988 Mon Sep 17 00:00:00 2001 From: J3m5 <5523410+J3m5@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:40:52 +0200 Subject: [PATCH 4/5] chore(readme): install commands reordering, fix iconify url, change Credits emoji --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 39c7101..e92b5f4 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,6 @@ It integrates seamlessly with the [API Platform](https://api-platform.com/) fram ## 📦 Installation -With [Yarn](https://yarnpkg.com/): - - yarn add @api-platform/api-doc-parser - Using [NPM](https://www.npmjs.com/): npm install @api-platform/api-doc-parser @@ -44,6 +40,10 @@ Using [Pnpm](https://pnpm.io/): pnpm add @api-platform/api-doc-parser +With [Yarn](https://yarnpkg.com/): + + yarn add @api-platform/api-doc-parser + Using [Bun](https://bun.sh/): bun add @api-platform/api-doc-parser @@ -90,7 +90,7 @@ parseGraphQl("https://demo.api-platform.com/graphql").then(({ api }) => ); ``` -## ![TypeScript](https://api.iconify.design/vscode-icons:file-type-typescript-official.svg?color=%23888888&wdith=26&height=26) Type definitions +## ![TypeScript](https://api.iconify.design/vscode-icons:file-type-typescript-official.svg?color=%23888888&width=26&height=26) Type definitions Each parse function returns a Promise that resolves to an object containing the normalized API structure, the raw documentation, and the HTTP status code: @@ -341,7 +341,7 @@ Contributions are welcome! To contribute: -## 🎉 Credits +## 🙌 Credits Created by [Kévin Dunglas](https://dunglas.fr). Sponsored by [Les-Tilleuls.coop](https://les-tilleuls.coop). From 07f2ed3094d719b3501d3b62b4a7a1fd1c958927 Mon Sep 17 00:00:00 2001 From: J3m5 <5523410+J3m5@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:46:56 +0200 Subject: [PATCH 5/5] chore(readme): refactor usage example with `await` and destructure all available properties --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e92b5f4..aa308db 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ Using [Bun](https://bun.sh/): ```javascript import { parseHydraDocumentation } from "@api-platform/api-doc-parser"; -parseHydraDocumentation("https://demo.api-platform.com").then(({ api }) => - console.log(api), +const { api, response, status } = await parseHydraDocumentation( + "https://demo.api-platform.com", ); ``` @@ -65,8 +65,8 @@ parseHydraDocumentation("https://demo.api-platform.com").then(({ api }) => ```javascript import { parseSwaggerDocumentation } from "@api-platform/api-doc-parser"; -parseSwaggerDocumentation("https://demo.api-platform.com/docs.json").then( - ({ api }) => console.log(api), +const { api, response, status } = await parseSwaggerDocumentation( + "https://demo.api-platform.com/docs.json", ); ``` @@ -75,9 +75,9 @@ parseSwaggerDocumentation("https://demo.api-platform.com/docs.json").then( ```javascript import { parseOpenApi3Documentation } from "@api-platform/api-doc-parser"; -parseOpenApi3Documentation( +const { api, response, status } = await parseOpenApi3Documentation( "https://demo.api-platform.com/docs.jsonopenapi?spec_version=3.0.0", -).then(({ api }) => console.log(api)); +); ``` **GraphQL** @@ -85,8 +85,8 @@ parseOpenApi3Documentation( ```javascript import { parseGraphQl } from "@api-platform/api-doc-parser"; -parseGraphQl("https://demo.api-platform.com/graphql").then(({ api }) => - console.log(api), +const { api, response } = await parseGraphQl( + "https://demo.api-platform.com/graphql", ); ```