Skip to content

Commit c6bb071

Browse files
committed
chore: adding vendor header in the parse response
Signed-off-by: Pawel Psztyc <jarrodek@gmail.com>
1 parent f29b05e commit c6bb071

11 files changed

+220
-390
lines changed

package-lock.json

Lines changed: 178 additions & 372 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@api-components/amf-web-api",
33
"description": "A web service parsing APIs with the AMF parser.",
4-
"version": "0.1.0",
4+
"version": "0.1.1",
55
"license": "Apache-2.0",
66
"main": "index.js",
77
"module": "index.js",
@@ -42,6 +42,7 @@
4242
"@types/koa": "^2.13.4",
4343
"@types/koa__router": "^8.0.9",
4444
"@types/mocha": "^9.0.0",
45+
"@types/unzipper": "^0.10.4",
4546
"@types/uuid": "^8.3.1",
4647
"chai": "^4.3.4",
4748
"chalk": "^4.1.2",

readme.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ Notes:
4747

4848
### Parsing a text content
4949

50-
This endpoints creates a task to parse the content. It does not wait for the parsing result. Instead iut returns the location of the endpoint to query for the parsing result.
50+
This endpoint creates a task to parse the content. It does not wait for the parsing result. Instead it returns the location of the endpoint to query for the parsing result.
5151

52-
The `x-api-vendor` is required and it describes API vendor. It is one of the API vendors supported by the AMF parser: `RAML 0.8`, `RAML 1.0`, `OAS 2.0`, `OAS 3.0`, `AMF Graph`, `JSON Schema`, `ASYNC 2.0`.
52+
The `x-api-vendor` is required and it is the API vendor to use. It is one of the API vendors supported by the AMF parser: `RAML 0.8`, `RAML 1.0`, `OAS 2.0`, `OAS 3.0`, and `ASYNC 2.0`.
5353

54-
The content type is optional and is ignored.
54+
The content type is optional and is ignored by the server. However, it is a good practice to keep it and set the correct value.
5555

5656
#### Plain text request
5757

@@ -91,11 +91,11 @@ Keep-Alive: timeout=5
9191

9292
### Parsing an API project in a zip file
9393

94-
To parse an entire project with multiple files send the zip file as the request body.
94+
To parse an entire API project with multiple files send a zip file in the request body.
9595

96-
You can set optional `x-entrypoint` header with the name of the API's main file (the entry point). When the header is not set then the server application tries to determine the best candidate using some heuristics.
96+
You can set an optional `x-entrypoint` header with the name of the API's main file (the entry point). When the header is not set then the server application tries to determine the best candidate using some built-in heuristics.
9797

98-
When multiple entrypoints are found in the project then the job status endpoint returns the list of files and the client should pick one (probably involving the user). After the pick is ready the client sends the PUT request to the job status endpoint (see below).
98+
When multiple entrypoints are found in the project then the job status endpoint returns the list of files with the 300 status code. The client should pick one (probably involving the user). After the pick is ready the client sends the PUT request to the job status endpoint (see below).
9999

100100
When a single endpoint is found in the API project then it is used automatically as the entrypoint. When no files are found then the process ends with an error.
101101

src/AmfParser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export class AmfParser {
178178
if (result.status === 'failed') {
179179
this.error = /** @type string */ (result.result);
180180
} else {
181-
this.result = /** @type string */ (result.result);
181+
this.result = /** @type any */ (result.result);
182182
}
183183
if (this.process.connected) {
184184
this.process.disconnect();

src/AmfService.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { AmfParser } from './AmfParser.js';
88
/** @typedef {import('../types').AmfProcessItem} AmfProcessItem */
99
/** @typedef {import('../types').ProcessingStatus} ProcessingStatus */
1010
/** @typedef {import('../types').ParserConfiguration} ParserConfiguration */
11+
/** @typedef {import('../types').ApiParsingResult} ApiParsingResult */
1112

1213
const timerSymbol = Symbol('timerSymbol');
1314

@@ -141,7 +142,7 @@ export class AmfService {
141142
/**
142143
* Reads the process' computation result.
143144
* @param {string} key The process key.
144-
* @returns {Promise<any>} The result
145+
* @returns {Promise<ApiParsingResult>} The result from the process.
145146
*/
146147
async getResult(key) {
147148
if (!this.processes.has(key)) {

src/ApiRoutes.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,12 @@ export class ApiRoutes {
146146
}
147147
if (status === 'finished') {
148148
const body = await this.service.getResult(key);
149+
ctx.set('x-api-vendor', body.vendor);
150+
const api = body.rendered;
149151
this.service.removeProcess(key);
150152
ctx.status = 200;
151153
ctx.type = 'application/ld+json';
152-
ctx.body = body;
154+
ctx.body = api;
153155
return;
154156
}
155157
if (status === 'running' || status === 'initialized') {

src/ParserProcess.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
/** @typedef {import('../types').ApiProjectParseCommand} ApiProjectParseCommand */
2424
/** @typedef {import('../types').ParserProcessResult} ParserProcessResult */
2525
/** @typedef {import('../types').ParserVendors} ParserVendors */
26+
/** @typedef {import('../types').ApiParsingResult} ApiParsingResult */
2627

2728
/**
2829
* The child process that performs the parsing job.
@@ -55,19 +56,22 @@ class AmfParserProcess {
5556
const { content, vendor } = command;
5657
const customResourceLoader = ResourceLoaderFactory.create(new ServerResourceLoader());
5758
try {
58-
const ro = new RenderOptions().withSourceMaps().withCompactUris().withPrettyPrint();
59+
const ro = new RenderOptions().withSourceMaps().withCompactUris();
5960
const apiConfiguration = this.getConfiguration(vendor).withRenderOptions(ro).withResourceLoader(customResourceLoader);
6061
const client = apiConfiguration.baseUnitClient();
6162
const result = await client.parseContent(content);
6263

6364
const wac = WebAPIConfiguration.fromSpec(result.sourceSpec);
64-
const waRo = new RenderOptions().withSourceMaps().withCompactUris().withPrettyPrint();
65+
const waRo = new RenderOptions().withSourceMaps().withCompactUris();
6566
const renderConfig = wac.withRenderOptions(waRo);
6667
const transformed = renderConfig.baseUnitClient().transform(result.baseUnit, PipelineId.Editing);
6768
const rendered = client.render(transformed.baseUnit, 'application/ld+json');
6869
process.send(/** @type ParserProcessResult */ ({
6970
status: 'finished',
70-
result: rendered,
71+
result: /** @type ApiParsingResult */ ({
72+
rendered,
73+
vendor,
74+
}),
7175
}));
7276
} catch (e) {
7377
process.send(/** @type ParserProcessResult */ ({
@@ -84,20 +88,23 @@ class AmfParserProcess {
8488
const { dir, entrypoint, vendor } = command;
8589
const customResourceLoader = ResourceLoaderFactory.create(new ServerResourceLoader(dir));
8690
try {
87-
const ro = new RenderOptions().withSourceMaps().withCompactUris().withPrettyPrint();
91+
const ro = new RenderOptions().withSourceMaps().withCompactUris();
8892
const apiConfiguration = this.getConfiguration(vendor).withRenderOptions(ro).withResourceLoader(customResourceLoader);
8993
const client = apiConfiguration.baseUnitClient();
9094
const location = path.join(dir, entrypoint);
9195
const result = await client.parse(`file://${location}`);
9296

9397
const wac = WebAPIConfiguration.fromSpec(result.sourceSpec).withResourceLoader(customResourceLoader);
94-
const waRo = new RenderOptions().withSourceMaps().withCompactUris().withPrettyPrint();
98+
const waRo = new RenderOptions().withSourceMaps().withCompactUris();
9599
const renderConfig = wac.withRenderOptions(waRo);
96100
const transformed = renderConfig.baseUnitClient().transform(result.baseUnit, PipelineId.Editing);
97101
const rendered = client.render(transformed.baseUnit, 'application/ld+json');
98102
process.send(/** @type ParserProcessResult */ ({
99103
status: 'finished',
100-
result: rendered,
104+
result: /** @type ApiParsingResult */ ({
105+
rendered,
106+
vendor,
107+
}),
101108
}));
102109
} catch (e) {
103110
process.send(/** @type ParserProcessResult */ ({

src/Server.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class Server {
4343
*
4444
* @param port When specified it closes a www server on a specific port. When not it stops all running http servers.
4545
*/
46-
stopHttp(port: number): Promise<void[]>;
46+
stopHttp(port?: number): Promise<void[]>;
4747

4848
/**
4949
* Starts the www over SSL server on a given port.
@@ -58,7 +58,7 @@ export class Server {
5858
*
5959
* @param port When specified it closes an ssl server on a specific port. When not it stops all running https servers.
6060
*/
61-
stopSsl(port: number): Promise<void[]>;
61+
stopSsl(port?: number): Promise<void[]>;
6262

6363
/**
6464
*

test/ApiProjectParsing.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ describe('Parsing the zip file content', () => {
111111
const { statusCode, headers, message } = result;
112112
assert.equal(statusCode, 200, 'has the 200 status code');
113113
assert.equal(headers['content-type'], 'application/ld+json', 'has the content-type header');
114+
assert.equal(headers['x-api-vendor'], 'RAML 1.0', 'has the x-api-vendor header');
114115
const body = JSON.parse(message.toString('utf-8'));
115116
assert.typeOf(body, 'object', 'has the response body');
116117
assert.typeOf(body['@graph'], 'array', 'has the graph response');

test/TextContentParsing.test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ describe('Parsing the text content', () => {
115115
const { statusCode, headers, message } = result;
116116
assert.equal(statusCode, 200, 'has the 200 status code');
117117
assert.equal(headers['content-type'], 'application/ld+json', 'has the content-type header');
118+
assert.equal(headers['x-api-vendor'], 'RAML 1.0', 'has the x-api-vendor header');
118119
const body = JSON.parse(message.toString('utf-8'));
119120
assert.typeOf(body, 'object', 'has the response body');
120121
assert.typeOf(body['@graph'], 'array', 'has the graph response');

types.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,14 @@ export interface ParserConfiguration {
8585
*/
8686
ttl?: number;
8787
}
88+
89+
export interface ApiParsingResult {
90+
/**
91+
* The AMF ld+json model.
92+
*/
93+
rendered: string;
94+
/**
95+
* The originating vendor.
96+
*/
97+
vendor: ParserVendors;
98+
}

0 commit comments

Comments
 (0)