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
-
-[](https://github.com/api-platform/api-doc-parser/actions?query=workflow%3ACI+branch%3Amain)
-[](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.
+
+
+ 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
+## 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
+
+
+
+
+
+
+
+
+
+## 🎉 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.
-
-
+# API Doc Parser
+
+**Effortlessly turn Hydra, Swagger/OpenAPI, and GraphQL specs into actionable data for your tools and apps.**
+
+[](https://github.com/api-platform/api-doc-parser/actions/workflows/ci.yml)
+[](https://github.com/api-platform/api-doc-parser/blob/main/LICENSE)
+[](https://bundlephobia.com/package/@api-platform/api-doc-parser)
+[](https://badge.fury.io/js/%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 }) =>
);
```
-## Type definitions
+##  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
-
-
-
+[](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
**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 }) =>
);
```
-##  Type definitions
+##  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",
);
```