Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: completed the conversion from postman to asyncapi #276

Merged
merged 12 commits into from
Sep 8, 2024
39 changes: 38 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
"license": "Apache-2.0",
"dependencies": {
"@asyncapi/parser": "^3.1.0",
"js-yaml": "^3.14.1"
"js-yaml": "^3.14.1",
"path": "^0.12.7",
"postman2openapi": "^1.2.1"
},
"devDependencies": {
"@jest/types": "^27.5.1",
Expand Down
17 changes: 16 additions & 1 deletion src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { converters as firstConverters } from "./first-version";
import { converters as secondConverters } from "./second-version";
import { converters as thirdConverters } from "./third-version";
import { converters as openapiConverters } from "./openapi";
import { converters as postmanConverters } from "./postman-collection";

import { serializeInput } from "./utils";

import type { AsyncAPIDocument, AsyncAPIConvertVersion, OpenAPIConvertVersion, ConvertOptions, ConvertFunction, ConvertOpenAPIFunction, OpenAPIDocument, OpenAPIToAsyncAPIOptions } from './interfaces';
import type { AsyncAPIDocument, AsyncAPIConvertVersion, OpenAPIConvertVersion, ConvertOptions, ConvertFunction, ConvertOpenAPIFunction, OpenAPIDocument, OpenAPIToAsyncAPIOptions, ConvertPostmanFunction } from './interfaces';

/**
* Value for key (version) represents the function which converts specification from previous version to the given as key.
Expand Down Expand Up @@ -78,3 +79,17 @@ export function convertOpenAPI(input: string | OpenAPIDocument, version: OpenAPI
}
return convertedAsyncAPI;
}

export function convertPostman(input: string, version: OpenAPIConvertVersion): string;
export function convertPostman(input: any, version: OpenAPIConvertVersion): AsyncAPIDocument;
export function convertPostman(input: string | any, version: OpenAPIConvertVersion): string | any {
const { format, document } = serializeInput(input);
const postmantoAsyncapiConverter = postmanConverters[version] as ConvertPostmanFunction;

const convertedAsyncAPI = postmantoAsyncapiConverter(document as any);

if (format === "yaml") {
return dump(convertedAsyncAPI, { skipInvalid: true });
}
return convertedAsyncAPI;
}
2 changes: 1 addition & 1 deletion src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ export type ConvertOptions = {
*/
export type ConvertFunction = (asyncapi: AsyncAPIDocument, options: ConvertOptions) => AsyncAPIDocument;
export type ConvertOpenAPIFunction = (openapi: OpenAPIDocument, options: OpenAPIToAsyncAPIOptions) => AsyncAPIDocument;

export type ConvertPostmanFunction = (postman: any) => AsyncAPIDocument;
ItshMoh marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const converters: Record<string, ConvertOpenAPIFunction > = {
* @param {ConvertOptions} options - Conversion options.
* @returns {AsyncAPIDocument} The converted AsyncAPI document.
*/
function from_openapi_to_asyncapi(openapi: OpenAPIDocument, options: OpenAPIToAsyncAPIOptions = {}): AsyncAPIDocument {
export function from_openapi_to_asyncapi(openapi: OpenAPIDocument, options: OpenAPIToAsyncAPIOptions = {}): AsyncAPIDocument {
const perspective = options.perspective || 'server';
const asyncapi: Partial<AsyncAPIDocument> = {
asyncapi: '3.0.0',
Expand Down
23 changes: 23 additions & 0 deletions src/postman-collection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import collection from '../../collection.json';
import { transpile } from 'postman2openapi';
import { from_openapi_to_asyncapi } from './openapi';
import { ConvertPostmanFunction } from 'interfaces';

export const converters: Record<string, ConvertPostmanFunction > = {
'3.0.0': from_postman_to_asyncapi
}

// Returns a JavaScript object representation of the OpenAPI definition.
const openapi = transpile(collection);

// console.log(JSON.stringify(openapi, null, 2));

function from_postman_to_asyncapi(postman: any) {
const openapi = transpile(postman);
const asyncapi = from_openapi_to_asyncapi(openapi);
return asyncapi;
}

const output = from_postman_to_asyncapi(collection);
// console.log(JSON.stringify(output, null, 2));

38 changes: 38 additions & 0 deletions test/input/postman/basic-collection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
info:
name: Sample Postman Collection
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
item:
- name: Sample Request
request:
method: GET
header: []
url:
raw: 'https://jsonplaceholder.typicode.com/posts/1'
protocol: https
host:
- jsonplaceholder
- typicode
- com
path:
- posts
- '1'
response: []
- name: Sample POST Request
request:
method: POST
header:
- key: Content-Type
value: application/json
body:
mode: raw
raw: '{ "title": "foo", "body": "bar", "userId": 1 }'
url:
raw: 'https://jsonplaceholder.typicode.com/posts'
protocol: https
host:
- jsonplaceholder
- typicode
- com
path:
- posts
response: []
22 changes: 22 additions & 0 deletions test/input/postman/header-authentication.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
info:
name: Headers and Authentication Test Collection
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
item:
- name: GET Request with Headers and Authentication
request:
method: GET
header:
- key: Authorization
value: Bearer your_token
- key: Accept
value: application/json
url:
raw: 'https://example.com/api/authenticated'
protocol: https
host:
- example
- com
path:
- api
- authenticated
response: []
72 changes: 72 additions & 0 deletions test/output/postman-to-asyncapi/basic-collection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
asyncapi: 3.0.0
info:
title: Sample Postman Collection
version: 1.0.0
servers:
typicode_com:
host: jsonplaceholder.typicode.com
protocol: https
channels:
posts_1:
address: /posts/1
messages:
sampleRequestResponse200:
name: sampleRequestResponse200
title: GET response 200
summary: ''
posts:
address: /posts
messages:
samplePostRequestRequest:
name: samplePostRequestRequest
title: POST request
contentType: application/json
payload:
schemaFormat: application/vnd.oai.openapi;version=3.0.0
schema:
type: object
properties:
body:
type: string
example: bar
title:
type: string
example: foo
userId:
type: number
example: 1
samplePostRequestResponse200:
name: samplePostRequestResponse200
title: POST response 200
summary: ''
operations:
sampleRequest:
action: receive
channel:
$ref: '#/channels/posts_1'
summary: Sample Request
description: Sample Request
bindings:
http:
method: GET
reply:
channel:
$ref: '#/channels/posts_1'
messages:
- $ref: '#/channels/posts_1/messages/sampleRequestResponse200'
samplePostRequest:
action: receive
channel:
$ref: '#/channels/posts'
summary: Sample POST Request
description: Sample POST Request
bindings:
http:
method: POST
messages:
- $ref: '#/channels/posts/messages/samplePostRequestRequest'
reply:
channel:
$ref: '#/channels/posts'
messages:
- $ref: '#/channels/posts/messages/samplePostRequestResponse200'
32 changes: 32 additions & 0 deletions test/output/postman-to-asyncapi/header-authentication.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
asyncapi: 3.0.0
info:
title: Headers and Authentication Test Collection
version: 1.0.0
servers:
example_com:
host: example.com
protocol: https
channels:
api_authenticated:
address: /api/authenticated
messages:
getRequestWithHeadersAndAuthenticationResponse200:
name: getRequestWithHeadersAndAuthenticationResponse200
title: GET response 200
summary: ''
operations:
getRequestWithHeadersAndAuthentication:
action: receive
channel:
$ref: '#/channels/api_authenticated'
summary: GET Request with Headers and Authentication
description: GET Request with Headers and Authentication
bindings:
http:
method: GET
reply:
channel:
$ref: '#/channels/api_authenticated'
messages:
- $ref: >-
#/channels/api_authenticated/messages/getRequestWithHeadersAndAuthenticationResponse200
20 changes: 20 additions & 0 deletions test/postman_to_asyncapi.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import fs from 'fs';
import path from 'path';
import { convertPostman } from '../src/convert';
import { assertResults } from './helpers';

describe("convert() - postman to asyncapi", () => {
it("should convert the basic structure of postman collection to asyncapi", () => {
const input = fs.readFileSync(path.resolve(__dirname, "input", "postman", "basic-collection.yml"), "utf8");
const output = fs.readFileSync(path.resolve(__dirname, "output", "postman-to-asyncapi", "basic-collection.yml"), "utf8");
const result = convertPostman(input, '3.0.0');
assertResults(output, result);
});

it("should convert headers and authentication from postman collection to asyncapi", () => {
const input = fs.readFileSync(path.resolve(__dirname, "input", "postman", "header-authentication.yml"), "utf8");
const output = fs.readFileSync(path.resolve(__dirname, "output", "postman-to-asyncapi", "header-authentication.yml"), "utf8");
const result = convertPostman(input, '3.0.0');
assertResults(output, result);
});
});
Loading