How I Created OpenApi (and why it still sucks)

How I Created OpenApi (and why it still sucks)

Sounds unbelievable right? But back when I was creating Java plugins to abstract the api communication logic from the business logic (see new api pattern), I showed a future OpenAPI steering committe, Kin Lane, about how to separate I/O State; this is what I called it (and still do) as it separates ALL DATA related to the request/response so that it could be shared with the services.

I first met Kin Lane at a talk he was doing with Tony Tam (creator of Swagger):

No alt text provided for this image

As you notice, Emmanual Paraskakis and Kin Lane both are on the steering committee:

No alt text provided for this image

I pointed out flaws in their work which caught the eye of Kin Lane.

On May 5, 2015 Kin Lane stated the following after reading my work on API Abstraction and API Chaining:

No alt text provided for this image
'?The shit you do is genius level stuff dude.?I had your API chaining stuff open for 2 months in a tab, and still haven't fully grocked everything, but am using it as core basis for the work I'm doing with Swagger, and next gen of mapping. I could use a personal walkthrough.'

He then asked me to write an article for his site going over these concepts.

At this time, OpenApi was still called Swagger 2.0 (and OpenAPI 3 was released until 2017). You can see the differences in the structure form one to the next here:

No alt text provided for this image

Post viewing my work, they changed:

  • parameters - the created a consolidated schema for all parameter definitions in 3.0
  • responses - they added response data to the spec in 3.0

In comparison, you can see an example Swagger 2.0 implementation here:

paths:
  /users:
    post:
      summary: Creates a new user.
      consumes:
        - application/json
      parameters:
        - in: body
          name: user
          description: The user to create.
          schema:
            type: object
            required:
              - userName
            properties:
              userName:
                type: string
              firstName:
                type: string
              lastName:
                type: string
      responses:
        201:
          description: Created        

And then in Swagger 3/OpenApi 3, they suddenly changes to have response data in their document and also have abstracted the common schema used for request/response.

paths:
  /users:
    get:
      summary: Gets a list of users.
      response:
        200:
          description: OK
          schema:
            $ref: '#/definitions/ArrayOfUsers'
        401:
          $ref: '#/responses/Unauthorized'   # <-----
  /users/{id}:
    get:
      summary: Gets a user by ID.
      response:
        200:
          description: OK
          schema:
            $ref: '#/definitions/User'
        401:
          $ref: '#/responses/Unauthorized'   # <-----
        404:
          $ref: '#/responses/NotFound'       # <-----
# Descriptions of common responses
responses:
  NotFound:
    description: The specified resource was not found
    schema:
      $ref: '#/definitions/Error'
  Unauthorized:
    description: Unauthorized
    schema:
      $ref: '#/definitions/Error'
definitions:
  # Schema for error response body
  Error:
    type: object
    properties:
      code:
        type: string
      message:
        type: string
    required:
      - code
      - message        

And if you look at my solution at the time, I had already internalized this properly (and even had ROLES associated so you could consume/produce different datasets per endpoint based on ROLE (it is also far less verbose):

	"CURRENTSTABLE": "1"
		"VERSION": {
			"1": {
				"DEFAULTACTION":"show",
		        "URI": {
		            "list": {
		             	"METHOD":"GET",
		            	"DESCRIPTION":"Show IOState",
		            	"ROLES":["ROLE_ADMIN","ROLE_ARCH"],
		            	"BATCH":["ROLE_ADMIN","ROLE_ARCH"],
		                "REQUEST": {
		                    "permitAll":[]
		                },
		                "RESPONSE": {
		                	"permitAll":["name"]
		                }
		            },        

Criticism on 'consumes' : I don't require 'consumes' for mime-type as this is function (not data); backend should always check the mime-type for the request and (if possible) automate the response to return data based on requested mime-type. So if someone requests in JSON, it returns JSON. If someone requests in XML, it returns XML, if someone requests in an unsupported mimetype, it throws an error. This is all function... not data. So the sent mime-type is not important to the document.

Criticism on Error codes: Error codes are internationalized in the api backend. By trying to duplicate this data in the document, you would need to internationalize EVERY SINGLE ONE of these error messages. This level of duplication shows that ERROR CODES are FUNCTION, not data and again do not belong in said doc.

Criticism on Headers: the only headers an api backend is REALLY concerned with is when dealing with CORS. And again, this is function and is standardized so does not need to be in the doc as it is a redundancy.

Plus abstraction of variables was added prior to OpenAPI's implementation:

	"NAME": "person"
	"NETWORKGRP": "public",
	"VALUES": {?
		"firstName": {
			"type": "String",
			"description": "",
			"mockData": "null_fname",
			"constraints": {"order":3,"isNullable":false},
		},
		"passwordExpired": {
			"type": "boolean",
			"description": "",
			"mockData": "false",
			"constraints": {"order":9,"isNullable":false},
		},
		"accountExpired": {
			"type": "boolean",
			"description": "",
			"mockData": "false",
			"constraints": {"order":10,"isNullable":false},
		},
		"oauthProvider": {
			"type": "String",
			"description": "",
			"mockData": "",
			"constraints": {"order":7,"isNullable":true},
		},
		"username": {
			"type": "String",
			"description": "",
			"mockData": "test",
			"constraints": {"isUnique":true,"order":1,"isBlank":false,"isNullable":false},
		},
		"accountLocked": {
			"type": "boolean",
			"description": "",
			"mockData": "false",
			"constraints": {"order":11,"isNullable":false},
		},
		"password": {
			"type": "String",
			"description": "",
			"mockData": "password",
			"constraints": {"order":2,"isBlank":false,"isNullable":false},
		},
		"lastName": {
			"type": "String",
			"description": "",
			"mockData": "null_lname",
			"constraints": {"order":4,"isNullable":false},
		},
		"oauthId": {
			"type": "String",
			"description": "",
			"mockData": "",
			"constraints": {"order":6,"isNullable":true},
		},
		"enabled": {
			"type": "boolean",
			"description": "",
			"mockData": "true",
			"constraints": {"order":12,"isNullable":false},
		},
		"avatarUrl": {
			"type": "String",
			"description": "",
			"mockData": "",
			"constraints": {"order":8,"isNullable":true},
		},
		"email": {
			"type": "String",
			"description": "",
			"mockData": "[email protected]",
			"constraints": {"isUnique":true,"maxSize":100,"order":5,"isEmail":true,"isNullable":false},
		},
		"id": {
			"key": "PKEY",
			"type": "Long",
			"description": "",
			"mockData": "112",
		},
		"version": {
			"type": "Long",
			"description": "",
			"mockData": "0",
		},
	},,        

NOTE: Keep in mind I already had working implementations in 2015 and people were using my tools. The beginning of my spec looked like this

SpringOne Conference talk

I also talked about these principles (as well as the abstraction requirements) at SpringOne, APIDays, APIWorld and other conferences.

The Netflix API manager at the time stated:

'This fixes everything we are currently having issues with'

So why doesn't OpenAPI give credit where credit is do? It's called Intellectual Property Theft and you can actually report this to the FBI (an office that Kin Lane has personal experience with):

No alt text provided for this image

Active working projects prior to OpenAPI

The first real implementation of 'shared IO state' was in the Grails api-toolkit plugin and a more mature version in the BEAPI-Framework.

The api-toolkit was using this methodology in 2014 (well before Kin Lane gave me credit for OpenAPI) so the functionality pre-dates OpenAPI by years.

Issues with Their Implementation

OpenAPI took some of the best parts of what I was doing and the worst parts of Swagger and slammed them together.

For example, I allow an api endpoint to declare various ways of calling them from the different ROLES that are sent in the token:

"show": 
		"METHOD": "GET",
		"DESCRIPTION": "Description for show",
			"ROLES": {
			"BATCH": ["ROLE_ADMIN"]
		},
		"REQUEST": {
			"permitAll":[],
			"ROLE_ADMIN":["id"]
		},
		"RESPONSE": {
			"permitAll": ["id","version","username","email","enabled","accountExpired"]
			}
	}        

So in the above, I can have 'permitAll' for all other ROLES calling this and then I can have ROLE_ADMIN declared so I can send an ID and get back data related to said ID and those not using an ID use their own user info sent from the token to return the data.

This allows for a common cathed object to be manipulated in different ways depending on the requesting ROLE

OpenAPI creates a security hole however by not supporting this (per the lead on the OpenAPI project).

OpenAPIalso adds in unecessary data like 'error codes' and messages; if you are calling this site from different countries, you would normally internationalize error messages in the application... but because of this, OpenAPI requires internationalization in BOTH PLACES (which can cause your data to get out of sync if it is not PERFECTLY up to date.

The difference between IO State and OpenAPI is that the data is properly abstracted away from the application so that the IO State doc IS the central version of truth; OpenAPI merely trys to duplicate the data that is HARDCODED thus making them impossible to sync.

Outcome

Regardless, I have forwarded this on to the FBI and contacted lawyers for prosecution of stealing my tools and ideas without proper compensation.

Checkmate openapi.

要查看或添加评论,请登录

Owen Rubel - API EXPERT的更多文章

  • OpenAPI Arazzo : Non-functional Call Flows

    OpenAPI Arazzo : Non-functional Call Flows

    So you by now have seen the drama. I opened an issue with Openapi Arazzo project talking about how they didn't address…

  • OpenAPI says Roy Fielding is WRONG!

    OpenAPI says Roy Fielding is WRONG!

    So as you all know, #OpenAPI maintainers love when I point out the issues with their 'standard' ..

  • Tech Jobs are Dead : The Doom of AI

    Tech Jobs are Dead : The Doom of AI

    Since the beginning of the year there have been hundreds of thousands of layoffs in the tech sector as the big 4 try to…

  • How To Kill Your Open Source Community

    How To Kill Your Open Source Community

    Back in 2015, the Grails framework was showing people how to simplify Java frameworks and make development fun. They…

  • Security as API Requirement

    Security as API Requirement

    Imagine going to McDonalds and ordering a burger and when you get it there is not MEAT! And when you ask them about it,…

    1 条评论
  • Why OpenAPI Adoption is Dropping

    Why OpenAPI Adoption is Dropping

    At the latest OpenAPI Meeting, it was brought up by the Meeting moderator that OpenAPI adoption is dropping and that…

  • Why Breaking Up Amazon Is In Everyones BEST Interests

    Why Breaking Up Amazon Is In Everyones BEST Interests

    NOTE: This article is now being BLOCKED after someone at Amazon Enterprise Support Escalations spotted the article this…

  • Recruiter Catfishing

    Recruiter Catfishing

    I get hit up constantly these days by recruiters..

    2 条评论
  • PostMan is NOT CI / CD

    PostMan is NOT CI / CD

    Calling an API, serving that API endpoint and mocking an api endpoint are all not the same thing. But the people at…

    19 条评论
  • OpenAPI Security Exploits

    OpenAPI Security Exploits

    In the past two days, yet another OpenApi exploit was found that elevates privileges on python. Why is this…

社区洞察

其他会员也浏览了