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

Documentation of migration structures #22

Merged
merged 1 commit into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ OpenAPI definitions and converters (for [typia](https://github.com/samchon/typia
2. [OpenAPI v3.0](https://github.com/samchon/openapi/blob/master/src/OpenApiV3.ts)
3. [OpenAPI v3.1](https://github.com/samchon/openapi/blob/master/src/OpenApiV3_1.ts)

Also, `@samchon/openapi` provides emended OpenAPI v3.1 definition and its converter/inverter from above versions for convenient development. The keyword "emended" means that [`OpenApi`](https://github.com/samchon/openapi/blob/master/src/OpenApi.ts) is not a direct OpenAPI v3.1 specification (OpenApiV3_1), but a little bit shrinked to remove ambiguous and duplicated expressions of OpenAPI v3.1 for the convenience of typia and nestia
Also, `@samchon/openapi` provides emended OpenAPI v3.1 definition and its converter/inverter from above versions for convenient development. The keyword "emended" means that [`OpenApi`](https://github.com/samchon/openapi/blob/master/src/OpenApi.ts) is not a direct OpenAPI v3.1 specification ([`OpenApiV3_1`](https://github.com/samchon/openapi/blob/master/src/OpenApiV3_1.ts)), but a little bit shrinked to remove ambiguous and duplicated expressions of OpenAPI v3.1 for the convenience of `typia` and `nestia`.

For example, when representing nullable type, OpenAPI v3.1 supports three ways. In that case, OpenApi remains only the third way, so that makes `typia` and `nestia` (especially [`@nestia/editor`](https://nestia.io/docs/editor/)) to be simple and easy to implement.

Expand All @@ -37,6 +37,9 @@ Here is the entire list of differences between OpenAPI v3.1 and emended OpenApi.
- Merge `OpenApiV3_1.IJsonSchema.IRecursiveReference` to `OpenApi.IJsonSchema.IReference`
- Merge `OpenApiV3_1.IJsonSchema.IAllOf` to `OpenApi.IJsonSchema.IObject`

Additionally, `@samchon/openapi` provides [`IMigrateDocument`](https://github.com/samchon/openapi/blob/master/src/IMigrateDocument.ts) for OpenAPI generators.




## How to use
Expand Down Expand Up @@ -71,10 +74,8 @@ const v3: OpenApiV3 = OpenApi.downgrade(output, "3.0");
OpenApi.downgrade(OpenApi.convert(v2), "3.0");
OpenApi.downgrade(OpenApi.convert(v3), "2.0");

// also supports openapi generator libraries
const migrate: IMigrateDocument = OpenApi.migrate(
OpenApi.convert(input),
);
// also helps openapi generator libraries
const migrate: IMigrateDocument = OpenApi.migrate(output);
```


Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@samchon/openapi",
"version": "0.2.1",
"version": "0.2.2",
"description": "OpenAPI definitions and converters for 'typia' and 'nestia'.",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
Expand Down Expand Up @@ -33,10 +33,10 @@
"@types/node": "^20.12.7",
"prettier": "^3.2.5",
"rimraf": "^5.0.5",
"ts-patch": "^3.1.2",
"typescript": "5.4.5",
"ts-patch": "^3.2.1",
"typescript": "^5.5.2",
"typescript-transform-paths": "^3.4.7",
"typia": "^6.2.2"
"typia": "^6.3.1"
},
"files": [
"lib",
Expand Down
42 changes: 42 additions & 0 deletions src/IMigrateDocument.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,57 @@
import { IMigrateRoute } from "./IMigrateRoute";
import { OpenApi } from "./OpenApi";

/**
* Document of migration.
*
* The `IMigrateDocument` interface is a document of migration from
* {@link OpenAPI.IDocument OpenAPI document} to RPC (Remote Procedure Call)
* functions; {@link IMigrateRoute}.
*
* As the `IMigrateDocument` and {@link IMigrateRoute} have a lot of special
* stories, when you're developing OpenAPI generator library, please read
* their descriptions carefully including the description of properties.
*
* @author Jeongho Nam - https://github.com/samchon
*/
export interface IMigrateDocument {
/**
* List of routes for migration.
*/
routes: IMigrateRoute[];

/**
* List of errors occurred during the migration.
*/
errors: IMigrateDocument.IError[];
}
export namespace IMigrateDocument {
/**
* Error of migration in the operation level.
*/
export interface IError {
/**
* Target operation causing the error.
*/
operation: () => OpenApi.IOperation;

/**
* Method of the operation.
*
* If the {@link OpenApi.IOperation.method} is not one of below type
* values, the operation would be ignored in the migration process for
* the RPC (Remote Procedure Call) function.
*/
method: "head" | "get" | "post" | "put" | "patch" | "delete";

/**
* Original path from the OpenAPI document.
*/
path: string;

/**
* List of error messages (reasons).
*/
messages: string[];
}
}
168 changes: 161 additions & 7 deletions src/IMigrateRoute.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,171 @@
import { OpenApi } from "./OpenApi";

/**
* Route information for migration.
*
* The `IMigrateRoute` is a structure representing a route information for
* OpenAPI generated RPC (Remote Procedure Call) function composed from the
* {@link OpenApi.IOperation OpenAPI operation}.
*
* As the `IMigrateRoute` has a lot of speical stories, when you're developing
* OpenAPI generator library, please read its description carefully including
* the description of its properties.
*
* @author Jeongho Nam - https://github.com/samchon
*/
export interface IMigrateRoute {
/**
* Method of the route.
*
* If the {@link OpenApi.IOperation.method} is not one of below type
* values, the operation would be ignored in the migration process for
* the RPC (Remote Procedure Call) function.
*/
method: "head" | "get" | "post" | "put" | "patch" | "delete";

/**
* Original path from the OpenAPI document.
*/
path: string;

/**
* Emended path for OpenAPI generator libraries.
*
* The difference between {@link path} is:
*
* 1. Path parameters are replaced with `:param` format.
* 2. Empty sub-paths are removed.
* 3. Do not starts with `/`.
*/
emendedPath: string;
accessor: string[]; // function accessor
parameters: IMigrateRoute.IParameter[]; // path parameters
headers: IMigrateRoute.IHeaders | null; // as an object
query: IMigrateRoute.IQuery | null; // as an object
body: IMigrateRoute.IBody | null; // request body
success: IMigrateRoute.IBody | null; // 200 or 201 status case
exceptions: Record<string, IMigrateRoute.IException>; // other status cases

/**
* Accessor for the route.
*
* The `accessor` is a list of string values that are representing how to
* access to the OpenAPI generated RPC (Remote Procedure Call) function
* through namespace(s).
*
* The `accessor` is composed with the following rules. At first, namespaces
* are composed by static directory names in the {@link path}. Parametric
* symbols represented by `:param` or `{param}` cannot be a part of the
* namespace.
*
* Instead, they would be a part of the function name. The function
* name is composed with the {@link method HTTP method} and parametric symbols
* like `getByParam` or `postByParam`. If there are multiple path parameters,
* they would be concatenated by `And` like `getByParam1AndParam2`.
*
* For refefence, if the {@link operation}'s {@link method} is `delete`, the
* function name would be replaced to `erase` instead of `delete`. It is
* the reason why the `delete` is a reserved keyword in many programming
* languages.
*
* - Exxample 1
* - path: `POST /shopping/sellers/sales`
* - accessor: `shopping.sellers.sales.post`
* - Example 2
* - endpoint: `GET /shoppings/sellers/sales/:saleId/reviews/:reviewId/comments/:id
* - accessor: `shoppings.sellers.sales.reviews.getBySaleIdAndReviewIdAndCommentId`
*/
accessor: string[];

/**
* List of path parameters.
*/
parameters: IMigrateRoute.IParameter[];

/**
* Metadata of headers.
*
* The `headers` property is a metadata of HTTP request headers for RPC function,
* including the parameter variable name and schema.
*
* Also, its {@link IMigrateRoute.IHeaders.schema} is always object or reference
* to object. Even though the original {@link OpenApi.IOperation OpenAPI operation}'s
* headers are separated to atomic typed properties, the `headers` property forcibly
* combines them into a single object type.
*
* For reference, if the `headers` property has been converted to an object type
* forcibly, its property {@link IMigrateRoute.IHeaders.name name} and
* {@link IMigrateRoute.IHeaders.key key} are always "headers".
*/
headers: IMigrateRoute.IHeaders | null;

/**
* Metadata of query values.
*
* The `query` property is a metadata of HTTP request query values for RPC function,
* including the parameter variable name and schema.
*
* Also, its {@link IMigrateRoute.IQuery.schema} is always object or reference
* to object. Even though the original {@link OpenApi.IOperation OpenAPI operation}'s
* query parameters are separated to atomic typed properties, the `query` property
* forcibly combines them into a single object type.
*
* For reference, if the `query` property has been converted to an object type
* forcibly, its property {@link IMigrateRoute.IQuery.name name} and
* {@link IMigrateRoute.IQuery.key key} are always "headers".
*/
query: IMigrateRoute.IQuery | null;

/**
* Metadata of request body.
*
* The `body` property is a metadata of HTTP request body for RPC function,
* including the parameter variable name, content type, and schema.
*
* If the `body` property is `null`, it means the operation does not require
* the request body data.
*/
body: IMigrateRoute.IBody | null;

/**
* Metadata of response body for success case.
*
* The `success` property is a metadata of HTTP response body for RPC function,
* including content type, and schema when status code is `200` or `201`.
*
* If the `success` property is `null`, it means the operation does not have
* the response body data. In other words, the RPC function would return `void`.
*/
success: IMigrateRoute.IBody | null;

/**
* Metadata of response body for exceptional status cases.
*
* The `exceptions` property is a metadata of HTTP response body for RPC
* function, including content type, and schema when status code is not `200`
* or `201`.
*
* The key of the `exceptions` property is the status code. It may be a
* stringified number, but sometimes it could be a string like "default",
* because the OpenAPI document allows the status code to be a string.
*/
exceptions: Record<string, IMigrateRoute.IException>;

/**
* Description comment for the route function.
*
* The `comment` is a function returning description comment for the
* RPC function of OpenAPI generated. The comment is composed with the
* following rules:
*
* 1. Starts from the {@link OpenApi.IOperation.summary} paragraph.
* 2. The next paragraphs are filled with {@link OpenApi.IOperation.description}.
* 3. Parameter descriptions are added with `@param` tag.
* 4. Security requirements are added with `@security` tag.
* 5. Tag names are added with `@tag` tag.
* 6. If {@link OpenApi.IOperation.deprecated}, `@deprecated` tag is added.
*/
comment: () => string;

/**
* Original operation from the OpenAPI document.
*
* The `operation` is a function returning the original
* {@link OpenApi.IOperation} from the {@link OpenAPI} document.
*/
operation: () => OpenApi.IOperation;
}
export namespace IMigrateRoute {
Expand Down
4 changes: 2 additions & 2 deletions src/internal/MigrateConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IMigrateRoute } from "../IMigrateRoute";
import { IMigrateDocument } from "../IMigrateDocument";
import { OpenApi } from "../OpenApi";
import { StringUtil } from "../utils/StringUtil";
import { MigrateOperationConverter } from "./MigrateOperationConverter";
import { MigrateRouteConverter } from "./MigrateRouteConverter";
import { MigrateRouteAccessor } from "./MigrateRouteAccessor";

export namespace MigrateConverter {
Expand All @@ -18,7 +18,7 @@ export namespace MigrateConverter {
.map((method) => {
const operation: OpenApi.IOperation = collection[method]!;
const migrated: IMigrateRoute | string[] =
MigrateOperationConverter.convert({
MigrateRouteConverter.convert({
document,
method,
path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Escaper } from "../utils/Escaper";
import { StringUtil } from "../utils/StringUtil";
import { OpenApiTypeChecker } from "./OpenApiTypeChecker";

export namespace MigrateOperationConverter {
export namespace MigrateRouteConverter {
export interface IProps {
document: OpenApi.IDocument;
method: "head" | "get" | "post" | "put" | "patch" | "delete";
Expand Down
Loading