GithubHelp home page GithubHelp logo

isabella232 / apidom Goto Github PK

View Code? Open in Web Editor NEW

This project forked from swagger-api/apidom

0.0 0.0 0.0 160.6 MB

Semantic parser for API specifications

Home Page: https://swagger-api.github.io/apidom/

JavaScript 4.77% TypeScript 95.14% HTML 0.07% SCSS 0.01% Shell 0.01%

apidom's Introduction

ApiDOM

Build Status Dependabot enabled

The purpose of ApiDOM is to provide a single, unifying structure for describing APIs across API description language and serialization formats. There currently exists several API description languages one can choose when defining an API, from OpenAPI, RAML or API Blueprint. There are also many serialization formats such as XML, YAML or JSON. Without a way to parse these formats to the same structure, developers are required to handle each format one-by-one, each in a different way and each translating to their internal domain model. This is tedious, time-consuming, and requires each maintainer to stay in step with every format they support.

ApiDOM solves this complex problem in a simple way. It allows parsers to parse to a single structure and allows tool builders to consume one structure for all formats.

Table of Contents

Getting started

Installation

ApiDOM is currently hosted on GitHub packages registry. For installing ApiDOM npm packages from GitHub packages registry, create .npmrc file in your current directory and add the following line to it:

@swagger-api:registry=https://npm.pkg.github.com

You can now install ApiDOM packages using npm:

 $ npm install @swagger-api/apidom-ast
 $ npm install @swagger-api/apidom-core
 $ npm install @swagger-api/apidom-ls
 $ npm install @swagger-api/apidom-ns-api-design-systems
 $ npm install @swagger-api/apidom-ns-asyncapi-2
 $ npm install @swagger-api/apidom-ns-openapi-3-1
 $ npm install @swagger-api/apidom-parser
 $ npm install @swagger-api/apidom-parser-adapter-asyncapi-json-2
 $ npm install @swagger-api/apidom-parser-adapter-asyncapi-yaml-2
 $ npm install @swagger-api/apidom-parser-adapter-json
 $ npm install @swagger-api/apidom-parser-adapter-openapi-json-3-1
 $ npm install @swagger-api/apidom-parser-adapter-openapi-yaml-3-1
 $ npm install @swagger-api/apidom-reference

For more information about installing npm packages from GitHub packages registry please visit Installing a package section in their documentation.

Usage

Every package of the monorepo has an associated README file demonstrating its purpose and containing usage examples.

ApiDOM Playground

ApiDOM Playground is a React application that runs in a browser and can visually demonstrate capabilities of the ApiDOM. ApiDOM Playground is build and deployed whenever the new commit lands on main branch.

image

ApiDOM Playground is available at https://swagger-api.github.io/apidom/

Development

This is a monorepo for all ApiDOM packages. All the code is written in TypeScript. All the information necessary for working with monorepo can be found in this article.

Prerequisites

Node.js >= 16.8.0 and npm >= 7.21.0 are the minimum required versions that this repo runs on. We recommend using the latest version of Node.js@16 though. We're using node-gyp to build some fragments that require Python 3.x. emscripten or docker needs to be installed on your operating system. We strongly recommend going with a docker option.

Setting up

Run the following commands to setup the repository for local development:

 $ npm i
 $ npm run build

Note: monorepo needs to be build in order for monorepo package topology for work correctly.

npm scripts

Some npm scripts run in parallel. Default maximum parallelization is set 2. This is due to the fact that our CI runs on GitHub Actions which uses GitHub hosted runners with 2-core CPUs. If you have computer with more than 2 CPU cores, you can speed running npm scripts by creating an environment variable called CPU_CORES and assign it a number of your CPU cores.

Assuming 4 CPU cores are available:

  $ export CPU_CORES=4
  $ npm run build

build scripts now runs much faster than before.

Build artifacts

 $ npm run build

Test

You must first build the artifacts before running tests.

 $ npm run test

Lint

 $ npm run lint

Check TypeScript types

 $ npm run typescript:check-types

Generate TypeScript types

 $ npm run typescript:declaration

Clean

 $ npm run clean

Build artifacts

All the packages have identical build system and expose build artifacts in identical way. After building artifacts, every package will contain five (5) additional directories. All the build artifacts are polymorphic - they can run in different environments like Web Browser, Node.js or Web Worker.

cjs/

This directory mirrors the structure of the codebase in src/. Contains ES5 compatible code with CommonJS style imports. Build fragments in this directory are ideal for Node.js and similar environments.

es/

This directory mirrors the structure of the codebase in src/. Contains ES5 compatible code with ES6 imports. Build fragments in this directory are ideal for bundling with Webpack or similar bundlers.

dist/

This directory contains bundled build fragments that use UMD modules. They're ideal for browser usage. The fragments are both in minified and un-minified form.

types/

TypeScript types generated from the source code.

Package mapping

Every package maps it's build artifacts in package.json file in following way:

"main": "cjs/index.js",
"module": "es/index.js",
"jsnext:main": "es/index.js",
"unpkg": "dist/apidom.browser.min.js",
"types": "types/index.d.ts",

To learn more about these fields please refer to webpack mainFields documentation.

Some packages produce build artifacts that are not isomorphic and instead code is written specifically for the client or the server. In that case package.json mapping looks like this:

"main": "cjs/adapter-node.js",
"module": "es/adapter-browser.js",
"jsnext:main": "es/adapter-browser.js",
"browser": "es/adapter-browser.js",
"unpkg": "dist/apidom-parser-apdater-json.browser.min.js",
"types": "types/adapter-browser.d.ts",

Using this monorepo as a local dev dependency

For using this monorepo as a local dev dependency for dependent project, following commands needs to be issued inside the monorepo directory after it has been cloned to a local filesystem:

 $ npm i
 $ npm run build
 $ npm run link

This will install the dependencies, built the monorepo and link all it's packages to global node_modules.

Usage in dependent project

Now that we have monorepo packages globally linked we can use them in dependent project. Let's say dependent project needs to directly use following packages:

  • @swagger-api/apidom-ast
  • @swagger-api/apidom-core

Issuing following command from inside the dependent project will link these packages:

 $ npm link @swagger-api/apidom-ast @swagger-api/apidom-core

If more packages (or all of them) need to be used in dependent project, they need to be explicitly enumerated using above command and separated by single empty space.

Notice that we link packages using single npm link command. This is necessary because of how npm link works internally. Always use single npm link command with multiple package names as argument.

Don't ever do this!

 $ npm link @swagger-api/apidom-ast
 $ npm link @swagger-api/apidom-core

Setting up npm script in depedent project can help keep things DRY.

Cleaning up

Dependent project

The best way to unlink monorepo packages from dependent project is to run following command inside the dependent project:

 $ npm i

Running npm i will remove the links to monorepo packages and install the packages from npm registry.

Note: running npm unlink <package-name> in dependent project will remove the link to monorepo package, but will leave the dependent project node_modules in corrupted state as there is no version of the package installed anymore. Running npm i is always a prefered way to restore your node_modules to original state.

ApiDOM monorepo

It is not necessary to unlink monorepo packages from global node_modules. But if you want to keep your global node_modules tidy you can run the following command in monorepo directory:

 $ npm run unlink

Running above npm script will unlink all monorepo packages from global node_modules.

If you want to just unlink particular monorepo packages, you have to enumerate them explicitly:

 $ npm unlink --global @swagger-api/apidom-ast @swagger-api/apidom-core

Contributing

This project uses swagger-api GitHub organizations contributing guide. You can obtain copy of this contributing guide at https://github.com/swagger-api/.github/blob/master/CONTRIBUTING.md. Read our contributing guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to ApiDOM.

Documentation

If there is one thing API description languages have taught us, it is that a single contract provides the best and fastest way to design and iterate on an API. Developers building the API can move independently as they progress towards the defined contract found in the OpenAPI or RAML document. Conversely, API consumers can build tools for consuming the API based on the API definition document.

This same pattern has proven to be just as valuable for building API description languages and tooling. ApiDOM is the contract for producing and consuming the many API description languages and serialization formats and allows everyone to move quickly and independently.

What is an Element ?

ApiDOM is made up of many small elements that have a rich semantic meaning given their value and context. An element is an individual piece that makes up an API, and can range from defining a resource to providing an example of an HTTP request.

The ApiDOM defines elements to be used for:

Describing an API Describing data structures used within that API Describing parse results when parsing API-related documents These elements also seek to provide a way to decouple APIs and their semantics from the implementation details.

The structure of an ApiDOM is recursive by nature. When looking for specific elements, it is best to traverse the ApiDOM tree to look for a match. Querying the ApiDOM tree will decouple our code from specific API description language. Also, it decouples our code from the specific structure of these documents as long as they are semantically equivalent.

As a way to annotate JSON

ApiDOM provides the ability to take a normal JSON structure and add a layer on top of it for the purpose of annotating and adding semantic data. Instead of creating an entirely different structure to describe the data, ApiDOM's approach is to expand the existing structure (we call it "refracting" a structure). Here is an example to show our point.

Take the following simple JSON object.

{
  "name": "John Doe",
  "email": "[email protected]"
}

Using ApiDOM, we can expand this out and add some human-readable titles and descriptions.

{
  "element": "object",
  "content": [
    {
      "element": "member",
      "meta": {
        "title": "Name",
        "description": "Name of a person"
      },
      "content": {
        "key": {
          "element": "string",
          "content": "name"
        },
        "value": {
          "element": "string",
          "content": "John Doe"
        }
      }
    },
    {
      "element": "member",
      "meta": {
        "title": "Email",
        "description": "Email address for the person"
      },
      "content": {
        "key": {
          "element": "string",
          "content": "email"
        },
        "value": {
          "element": "string",
          "content": "[email protected]"
        }
      }
    }
  ]
}

We added some semantic data to the existing data, but we did so while retaining the semantic structure of the data with the object and string elements. This means there is no semantic difference in the ApiDOM structure and the original JSON structure. It also means we can add extra semantics on top of these structural ones.

As a unifying structure

You may have noticed the similarities between the JSON example above and XML. XML has elements, attributes, and content. It would be a good question to ask if we simply turned JSON into XML.

ApiDOM is actually meant to provide these cross-format similarities. It means that a JSON structure may be refracted and converted to XML. It also means an XML document may be converted into ApiDOM. This also goes for YAML, HTML, CSV, and many other formats. ApiDOM is a way to use refracting to unify these structures.

Let's look at another example, this time refacting XML with ApiDOM.

<person name="John Doe" email="[email protected]">

This example in refracted form would look like the following snippet. Notice that we're using attributes in resulting ApiDOM structure.

{
  "element": "person",
  "attributes": {
    "name": {
      "element": "string",
      "content": "John Doe"
    },
    "email": {
      "element": "string",
      "content": "[email protected]"
    }
  }
}

Since we can go back and forth between JSON, YAML, XML, and other formats, we are now able to use same toolset across the different formats. That means we could use XSLT to transform JSON documents.

As a queryable structure

ApiDOM is meant to free us from the structure of our documents, similar to how XML does with things like XPATH or the DOM. It means we can now query JSON documents as if there was an underlying DOM, which decouples our SDK from our structure and our structure from our data.

ApiDOM stages

There are three stages to ApiDOM

  • Parse stage
  • Refract stage
  • Generate stage

Parse stage

The parse stage takes JSON string and produces ApiDOM structure using the base ApiDOM namespace. There are two phases of parsing:

  • Lexical Analysis phase
  • Syntactic Analysis phase
Lexical Analysis phase

Lexical Analysis will take a JSON string and turn it into a stream of tokens. tree-sitter / web-tree-sitter is used as an underlying lexical analyzer.

Syntactic Analysis

Syntactic Analysis will take a stream of tokens and turn it into an ApiDOM representation. CST produced by lexical analysis is syntactically analyzed, and ApiDOM structure using base (generic) ApiDOM namespace is produced. Syntactic analysis can further be direct or indirect. JSON parser has both direct and indirect syntactical analyzers, but YAML parser only has an indirect one.

Direct Syntactical analysis

This analysis directly turns tree-sitter CST into ApiDOM. Single traversal is required, which makes it super performant, and it's the default analysis used.

Indirect Syntactic analysis

This analysis turns trees-sitter CST into JSON AST representation. Then JSON AST is turned into ApiDOM. Two traversals are required, which makes the indirect analysis less performant than the direct one. Though less performant, having JSON AST representation allows us to do further complex analysis.

Refract stage

The refract stage takes a generic ApiDOM structure (base namespace) and traverses through it, adding, updating, and removing nodes as it goes along and turning it into semantic ApiDOM structure (like OpenAPI or AsyncAPI). This is by far the most complex part of ApiDOM. This is where plugins operate. If plugins are used, additional traversal is currently needed.

Generate stage

We can currently only generate JSON documents from the ApiDOM structure. It doesn't matter if the original document was originally defined in JSON or YAML. Generated JSON documented will have exactly the same semantic information as the original one, but the style information from the original document is not preserved (white spaces/comments, etc..).


Having said that, this is how JSON OpenAPI 3.1 document gets transformed into ApiDOM:

with direct syntactic analysis (requires 2 traversals)

JSON string -> tree-sitter CST ->  generic ApiDOM -> OpenAPI 3.1 ApiDOM

with indirect syntactic analysis (requires 3 traversals)

JSON string -> tree-sitter CST -> JSON AST -> generic ApiDOM -> OpenAPI 3.1 ApiDOM

with direct syntactic analysis and additional plugins (requires 3 traversal)

JSON string -> tree-sitter CST -> generic ApiDOM -> OpenAPI 3.1 ApiDOM -> plugins -> OpenAPI 3.1 ApiDOM

This very closely reflects how Babel works. Their transform phase is our refract phase. The only difference is that when plugins are involved, our transform phase requires 2 traversals instead of a single one. We can find a way in the future how to fold these 2 traversals into a single one.

License

ApiDOM is licensed under Apache 2.0 license. ApiDOM comes with an explicit NOTICE file containing additional legal notices and information.

This project uses REUSE specification that defines a standardized method for declaring copyright and licensing for software projects.

Software Bill Of Materials (SBOM)

Software Bill Of materials is available in apidom.spdx.yaml using SPDX language.

apidom's People

Contributors

char0n avatar dependabot[bot] avatar tim-lai avatar frantuma avatar swagger-bot avatar ponelat avatar a-abella avatar mend-for-github-com[bot] avatar martinloewinger avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.