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

openapi-types: Extract HTTP methods to enum to allow programmatic access #713

Conversation

Envek
Copy link
Contributor

@Envek Envek commented Mar 4, 2021

If I want programmatically inspect or preprocess spec, then I'm in trouble when I want to iterate over all possible HTTP methods inside every path, I have to duplicate list of HTTP from spec's PathItemObject verbs in my code, and after that TypeScript will throw an error because it can't figure out that all of array elements are declared in PathItemObject type definition:

import { OpenAPIV3 } from "openapi-types"

const apiSpec: <OpenAPIV3.Document> = {}

for (const methods of Object.values(schema.paths)) {
    for (const method of ["get", "post", "put", "delete", "options", "head", "patch", "trace"]) {
      const pathItem = methods[method] // ERROR!
      //               ~~~~~~~~~~~~~~~
      // Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'PathItemObject'.
      //   No index signature with a parameter of type 'string' was found on type 'PathItemObject'. ts(7053)

Thankfully, in TypeScript we can declare enums and use their keys and values in runtime, like this:

enum HttpMethods {
    GET = 'get',
    PUT = 'put',
    POST = 'post',
    DELETE = 'delete',
}

Object.values(HttpMethods).map(values => )

So, by adding such an enum and rewriting PathItemObject using it as index signature, we can do following:

import { OpenAPIV3 } from "openapi-types"

const apiSpec: <OpenAPIV3.Document> = {}

for (const methods of Object.values(schema.paths)) {
    for (const method of Object.values(OpenAPIV3.HttpMethods)) {
      const pathItem = methods[method] // ok, method definitely is one of HttpMethods values and pathItem is a pathItemObject

Sure, I can define such an enum in my code (and add some additional type casting), but I think that keeping it in the package is the right thing.

As a side effect, PathItemObject definitions became a little bit more self-documented (here are metadata and here are http verbs with corresponding OperationObjects).

Notes

  • I had to convert interfaces to types because of following error if I tried to add index signature to an interface:

    export interface PathItemObject<T extends {} = {}> {
      $ref?: string;
      parameters?: Parameters;
      [method:HttpMethods]: OperationObject<T>;
    // ~~~~~~
    // An index signature parameter type cannot be a union type. Consider using a mapped object type instead.ts(1337)

    Types and interfaces are almost the same, but TypeScript doesn't allow to add new properties to existing types. See Advanced Types / Interfaces vs. Type Aliases. Not sure how crucial it is.

  • As set of allowed HTTP verbs for OpenAPI 2 and 3 is different (OpenAPI 3 allows TRACE while OpenAPI 2 does not), I had to create separate enums.

  • For OpenAPI 2 PathItemObject there was DEL HTTP verb specified, however it doesn't exist in the spec. It was added along with other types on openapi-types package creation and I couldn't find any reasons why it exists. So I dropped it.

@jsdevel jsdevel merged commit d3f7df6 into kogosoftwarellc:master Apr 8, 2021
@Envek Envek deleted the openapi-types/extract-http-methods-to-enum branch April 12, 2021 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants