Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@api-platform/api-doc-parser

Package Overview
Dependencies
Maintainers
6
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@api-platform/api-doc-parser - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

lib/hydra/addParameters.js

22

lib/hydra/parseHydraDocumentation.js

@@ -44,2 +44,6 @@ "use strict";

var _addParameters = require("./addParameters");
var _addParameters2 = _interopRequireDefault(_addParameters);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -444,3 +448,4 @@

operations: resourceOperations,
deprecated: (0, _lodash2.default)(relatedClass, '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', false)
deprecated: (0, _lodash2.default)(relatedClass, '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', false),
parameters: []
}));

@@ -503,10 +508,17 @@ }

});
}, function (_ref2) {
var response = _ref2.response;
}, function (data) {
return _promise2.default.reject({
api: new _Api2.default(entrypointUrl, { resources: [] }),
response: response,
status: (0, _lodash2.default)(response, "status")
error: data,
response: data.response,
status: (0, _lodash2.default)(data.response, "status")
});
}).then(function (_ref2) {
var api = _ref2.api,
response = _ref2.response,
status = _ref2.status;
return (0, _addParameters2.default)(api).then(function (api) {
return { api: api, response: response, status: status };
});
});
}

@@ -27,2 +27,6 @@ "use strict";

var _Parameter = require("./Parameter");
var _Parameter2 = _interopRequireDefault(_Parameter);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -29,0 +33,0 @@

{
"name": "@api-platform/api-doc-parser",
"version": "0.5.0",
"version": "0.6.0",
"description": "Transform a Hydra API documentation in an intermediate representation that can be used for various tasks such as creating smart API clients, scaffolding code or building admininistration interfaces.",

@@ -32,3 +32,3 @@ "files": [

"flow-bin": "^0.42.0",
"jest": "^20.0.0",
"jest": "^23.0.0",
"jest-fetch-mock": "^1.0.8",

@@ -47,3 +47,4 @@ "prettier": "^1.12.1"

"eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check",
"build": "babel src -d lib --ignore '*.test.js'"
"build": "babel src -d lib --ignore '*.test.js'",
"watch": "babel src -d lib --ignore '*.test.js' --watch"
},

@@ -50,0 +51,0 @@ "jest": {

@@ -7,3 +7,3 @@ # API Doc Parser

`api-doc-parser` is a JavaScript (ES6) library to parse [Hydra](http://hydra-cg.com) API documentations and transform them
`api-doc-parser` is a JavaScript (ES6) library to parse [Hydra](http://hydra-cg.com) or Swagger API documentations and transform them
in an intermediate representation. This data structure can then be used for various tasks such as creating smart API clients,

@@ -30,2 +30,3 @@ scaffolding code or building administration interfaces.

**Hydra**
```javascript

@@ -37,6 +38,13 @@ import parseHydraDocumentation from 'api-doc-parser/lib/hydra/parseHydraDocumentation';

## Support for other formats (GraphQL, Swagger/OpenAPI, JSONAPI...)
**Swagger**
```javascript
import parseSwaggerDocumentation from 'api-doc-parser/lib/swagger/parseSwaggerDocumentation';
parseSwaggerDocumentation('https://demo.api-platform.com/docs.json').then(({api}) => console.log(api));
```
## Support for other formats (GraphQL, JSONAPI...)
API Doc Parser is designed to parse any API documentation format and convert it in the same intermediate representation.
For now, only Hydra is supported but if you develop a parser for another format, please [open a Pull Request](https://github.com/dunglas/api-doc-parser/pulls)
For now, only Hydra and Swagger is supported but if you develop a parser for another format, please [open a Pull Request](https://github.com/dunglas/api-doc-parser/pulls)
to include it in the library.

@@ -43,0 +51,0 @@

@@ -8,2 +8,3 @@ import { promises } from "jsonld";

import fetchJsonLd from "./fetchJsonLd";
import addParameters from "./addParameters";

@@ -194,125 +195,171 @@ /**

return fetchEntrypointAndDocs(entrypointUrl, options).then(
({ entrypoint, docs, response }) => {
const resources = [],
fields = [],
operations = [];
const title = get(
docs,
'[0]["http://www.w3.org/ns/hydra/core#title"][0]["@value"]',
"API Platform"
);
const entrypointType = get(entrypoint, '[0]["@type"][0]');
if (!entrypointType) {
throw new Error('The API entrypoint has no "@type" key.');
}
const entrypointClass = findSupportedClass(docs, entrypointType);
if (
!Array.isArray(
entrypointClass["http://www.w3.org/ns/hydra/core#supportedProperty"]
)
) {
throw new Error(
'The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.'
return fetchEntrypointAndDocs(entrypointUrl, options)
.then(
({ entrypoint, docs, response }) => {
const resources = [],
fields = [],
operations = [];
const title = get(
docs,
'[0]["http://www.w3.org/ns/hydra/core#title"][0]["@value"]',
"API Platform"
);
}
// Add resources
for (const properties of entrypointClass[
"http://www.w3.org/ns/hydra/core#supportedProperty"
]) {
const readableFields = [],
resourceFields = [],
writableFields = [],
resourceOperations = [];
const entrypointType = get(entrypoint, '[0]["@type"][0]');
if (!entrypointType) {
throw new Error('The API entrypoint has no "@type" key.');
}
const property = get(
properties,
'["http://www.w3.org/ns/hydra/core#property"][0]'
);
if (!property) {
continue;
const entrypointClass = findSupportedClass(docs, entrypointType);
if (
!Array.isArray(
entrypointClass["http://www.w3.org/ns/hydra/core#supportedProperty"]
)
) {
throw new Error(
'The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.'
);
}
// Add fields
const relatedClass = findRelatedClass(docs, property);
for (const supportedProperties of relatedClass[
// Add resources
for (const properties of entrypointClass[
"http://www.w3.org/ns/hydra/core#supportedProperty"
]) {
const supportedProperty = get(
supportedProperties,
const readableFields = [],
resourceFields = [],
writableFields = [],
resourceOperations = [];
const property = get(
properties,
'["http://www.w3.org/ns/hydra/core#property"][0]'
);
const range = get(
supportedProperty,
'["http://www.w3.org/2000/01/rdf-schema#range"][0]["@id"]',
null
);
if (!property) {
continue;
}
const field = new Field(
supportedProperty["http://www.w3.org/2000/01/rdf-schema#label"][0][
"@value"
],
{
id: supportedProperty["@id"],
range: range,
reference:
"http://www.w3.org/ns/hydra/core#Link" ===
get(property, '["@type"][0]')
? range
: null, // Will be updated in a subsequent pass
required: get(
// Add fields
const relatedClass = findRelatedClass(docs, property);
for (const supportedProperties of relatedClass[
"http://www.w3.org/ns/hydra/core#supportedProperty"
]) {
const supportedProperty = get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#property"][0]'
);
const range = get(
supportedProperty,
'["http://www.w3.org/2000/01/rdf-schema#range"][0]["@id"]',
null
);
const field = new Field(
supportedProperty[
"http://www.w3.org/2000/01/rdf-schema#label"
][0]["@value"],
{
id: supportedProperty["@id"],
range: range,
reference:
"http://www.w3.org/ns/hydra/core#Link" ===
get(property, '["@type"][0]')
? range
: null, // Will be updated in a subsequent pass
required: get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#required"][0]["@value"]',
false
),
description: get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#description"][0]["@value"]',
""
),
maxCardinality: get(
supportedProperty,
'["http://www.w3.org/2002/07/owl#maxCardinality"][0]["@value"]',
null
),
deprecated: get(
supportedProperties,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',
false
)
}
);
fields.push(field);
resourceFields.push(field);
if (
get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#required"][0]["@value"]',
false
),
description: get(
'["http://www.w3.org/ns/hydra/core#readable"][0]["@value"]'
)
) {
readableFields.push(field);
}
if (
get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#description"][0]["@value"]',
""
),
maxCardinality: get(
supportedProperty,
'["http://www.w3.org/2002/07/owl#maxCardinality"][0]["@value"]',
null
),
deprecated: get(
supportedProperties,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',
false
'["http://www.w3.org/ns/hydra/core#writable"][0]["@value"]'
)
) {
writableFields.push(field);
}
);
}
fields.push(field);
resourceFields.push(field);
// parse entrypoint's operations (a.k.a. collection operations)
if (property["http://www.w3.org/ns/hydra/core#supportedOperation"]) {
for (const entrypointOperation of property[
"http://www.w3.org/ns/hydra/core#supportedOperation"
]) {
if (
!entrypointOperation["http://www.w3.org/ns/hydra/core#returns"]
) {
continue;
}
if (
get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#readable"][0]["@value"]'
)
) {
readableFields.push(field);
}
const range =
entrypointOperation[
"http://www.w3.org/ns/hydra/core#returns"
][0]["@id"];
const operation = new Operation(
entrypointOperation[
"http://www.w3.org/2000/01/rdf-schema#label"
][0]["@value"],
{
method:
entrypointOperation[
"http://www.w3.org/ns/hydra/core#method"
][0]["@value"],
expects:
entrypointOperation[
"http://www.w3.org/ns/hydra/core#expects"
] &&
entrypointOperation[
"http://www.w3.org/ns/hydra/core#expects"
][0]["@id"],
returns: range,
types: entrypointOperation["@type"],
deprecated: get(
entrypointOperation,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',
false
)
}
);
if (
get(
supportedProperties,
'["http://www.w3.org/ns/hydra/core#writable"][0]["@value"]'
)
) {
writableFields.push(field);
resourceOperations.push(operation);
operations.push(operation);
}
}
}
// parse entrypoint's operations (a.k.a. collection operations)
if (property["http://www.w3.org/ns/hydra/core#supportedOperation"]) {
for (const entrypointOperation of property[
// parse resource operations (a.k.a. item operations)
for (const supportedOperation of relatedClass[
"http://www.w3.org/ns/hydra/core#supportedOperation"
]) {
if (
!entrypointOperation["http://www.w3.org/ns/hydra/core#returns"]
!supportedOperation["http://www.w3.org/ns/hydra/core#returns"]
) {

@@ -323,7 +370,7 @@ continue;

const range =
entrypointOperation["http://www.w3.org/ns/hydra/core#returns"][0][
supportedOperation["http://www.w3.org/ns/hydra/core#returns"][0][
"@id"
];
const operation = new Operation(
entrypointOperation[
supportedOperation[
"http://www.w3.org/2000/01/rdf-schema#label"

@@ -333,16 +380,16 @@ ][0]["@value"],

method:
entrypointOperation[
supportedOperation[
"http://www.w3.org/ns/hydra/core#method"
][0]["@value"],
expects:
entrypointOperation[
supportedOperation[
"http://www.w3.org/ns/hydra/core#expects"
] &&
entrypointOperation[
supportedOperation[
"http://www.w3.org/ns/hydra/core#expects"
][0]["@id"],
returns: range,
types: entrypointOperation["@type"],
types: supportedOperation["@type"],
deprecated: get(
entrypointOperation,
supportedOperation,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',

@@ -357,91 +404,56 @@ false

}
}
// parse resource operations (a.k.a. item operations)
for (const supportedOperation of relatedClass[
"http://www.w3.org/ns/hydra/core#supportedOperation"
]) {
if (!supportedOperation["http://www.w3.org/ns/hydra/core#returns"]) {
continue;
const url = get(entrypoint, `[0]["${property["@id"]}"][0]["@id"]`);
if (!url) {
throw new Error(`Unable to find the URL for "${property["@id"]}".`);
}
const range =
supportedOperation["http://www.w3.org/ns/hydra/core#returns"][0][
"@id"
];
const operation = new Operation(
supportedOperation["http://www.w3.org/2000/01/rdf-schema#label"][0][
"@value"
],
{
method:
supportedOperation["http://www.w3.org/ns/hydra/core#method"][0][
"@value"
],
expects:
supportedOperation["http://www.w3.org/ns/hydra/core#expects"] &&
supportedOperation[
"http://www.w3.org/ns/hydra/core#expects"
][0]["@id"],
returns: range,
types: supportedOperation["@type"],
resources.push(
new Resource(guessNameFromUrl(url, entrypointUrl), url, {
id: relatedClass["@id"],
title: get(
relatedClass,
'["http://www.w3.org/ns/hydra/core#title"][0]["@value"]',
""
),
fields: resourceFields,
readableFields,
writableFields,
operations: resourceOperations,
deprecated: get(
supportedOperation,
relatedClass,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',
false
)
}
),
parameters: []
})
);
resourceOperations.push(operation);
operations.push(operation);
}
const url = get(entrypoint, `[0]["${property["@id"]}"][0]["@id"]`);
if (!url) {
throw new Error(`Unable to find the URL for "${property["@id"]}".`);
// Resolve references
for (const field of fields) {
if (null !== field.reference) {
field.reference =
resources.find(resource => resource.id === field.reference) ||
null;
}
}
resources.push(
new Resource(guessNameFromUrl(url, entrypointUrl), url, {
id: relatedClass["@id"],
title: get(
relatedClass,
'["http://www.w3.org/ns/hydra/core#title"][0]["@value"]',
""
),
fields: resourceFields,
readableFields,
writableFields,
operations: resourceOperations,
deprecated: get(
relatedClass,
'["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]',
false
)
})
);
}
// Resolve references
for (const field of fields) {
if (null !== field.reference) {
field.reference =
resources.find(resource => resource.id === field.reference) || null;
}
}
return Promise.resolve({
api: new Api(entrypointUrl, { title, resources }),
response,
status: response.status
});
},
({ response }) =>
Promise.reject({
api: new Api(entrypointUrl, { resources: [] }),
response,
status: get(response, "status")
})
);
return Promise.resolve({
api: new Api(entrypointUrl, { title, resources }),
response,
status: response.status
});
},
data =>
Promise.reject({
api: new Api(entrypointUrl, { resources: [] }),
error: data,
response: data.response,
status: get(data.response, "status")
})
)
.then(({ api, response, status }) =>
addParameters(api).then(api => ({ api, response, status }))
);
}

@@ -555,2 +555,21 @@ import parseHydraDocumentation from "./parseHydraDocumentation";

const resourceCollection = `{
"hydra:search": {
"hydra:mapping": []
}
}`;
const resourceCollectionWithParameters = `{
"hydra:search": {
"hydra:mapping": [
{
"property": "isbn",
"variable": "isbn",
"range": "http://www.w3.org/2001/XMLSchema#string",
"required": false
}
]
}
}`;
const book = {

@@ -747,3 +766,11 @@ name: "books",

],
deprecated: false
deprecated: false,
parameters: [
{
variable: "isbn",
range: "http://www.w3.org/2001/XMLSchema#string",
required: false,
description: ""
}
]
};

@@ -891,3 +918,4 @@

],
deprecated: false
deprecated: false,
parameters: []
};

@@ -1018,3 +1046,4 @@

],
deprecated: false
deprecated: false,
parameters: []
};

@@ -1079,9 +1108,12 @@

],
deprecated: true
deprecated: true,
parameters: []
};
const resources = [book, review, customResource, deprecatedResource];
const expectedApi = {
entrypoint: "http://localhost",
title: "API Platform's demo",
resources: [book, review, customResource, deprecatedResource]
resources: resources
};

@@ -1099,8 +1131,15 @@

test("parse a Hydra documentation", () => {
fetch.mockResponses([entrypoint, init], [docs, init]);
test("parse a Hydra documentation", async () => {
fetch.mockResponses(
[entrypoint, init],
[docs, init],
[resourceCollectionWithParameters, init],
[resourceCollection, init],
[resourceCollection, init],
[resourceCollection, init]
);
const options = { headers: new Headers({ CustomHeader: "customValue" }) };
return parseHydraDocumentation("http://localhost", options).then(data => {
await parseHydraDocumentation("http://localhost", options).then(data => {
expect(JSON.stringify(data.api, null, 2)).toBe(

@@ -1112,4 +1151,5 @@ JSON.stringify(expectedApi, null, 2)

expect(fetch).toHaveBeenCalledTimes(2);
expect(fetch).toHaveBeenLastCalledWith(
expect(fetch).toHaveBeenCalledTimes(2 + resources.length);
expect(fetch).toHaveBeenNthCalledWith(
2,
"http://localhost/docs.jsonld",

@@ -1121,6 +1161,13 @@ options

test("parse a Hydra documentation (http://localhost/)", () => {
fetch.mockResponses([entrypoint, init], [docs, init]);
test("parse a Hydra documentation (http://localhost/)", async () => {
fetch.mockResponses(
[entrypoint, init],
[docs, init],
[resourceCollectionWithParameters, init],
[resourceCollection, init],
[resourceCollection, init],
[resourceCollection, init]
);
return parseHydraDocumentation("http://localhost/").then(data => {
await parseHydraDocumentation("http://localhost/").then(data => {
expect(JSON.stringify(data.api, null, 2)).toBe(

@@ -1127,0 +1174,0 @@ JSON.stringify(expectedApi, null, 2)

@@ -5,2 +5,3 @@ // @flow

import Operation from "./Operation";
import Parameter from "./Parameter";

@@ -13,2 +14,3 @@ type ResourceOptions = {

writableFields?: Field[],
parameters?: Parameter[],
operations?: Operation[]

@@ -15,0 +17,0 @@ };

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc