Giter Club home page Giter Club logo

swaxios's People

Contributors

bennycode avatar dependabot-preview[bot] avatar dependabot[bot] avatar ffflorian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

swaxios's Issues

Extract types

Currently, the return values of the methods are inline interfaces. This way they cannot be used to type any attributes. I would like to use the types for typing a vuex store, but would have to recreate them for this use case. It would be great if one could extract the types and reuse them in other parts of the application.

BUG: Delete endpoint always returns void

Input

   "/api/v1/account/{id}": {
      "delete": {
        "consumes": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "type": "number"
          }
        ],
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "",
            "schema": {
              "type": "number"
            }
          }
        },
        "tags": [
          "account"
        ]
      },

Output (buggy)

  async deleteById(id: number): Promise<void> {
    const resource = `/api/v1/account/${id}`;
    await this.apiClient.delete(resource);
  }

Additional service (naming) generating option

Currently, the names of the services are generated by the path of the request. This could split up services which might belong together. For example, on the server side i have a service for notifications, there are /api/notifications get and put routes, so i will get a notificationService. But i also have a url like this /api/notifications/stream which is used for SSE. This route will create a new folder notifications next to the NotificationService.ts file which contains a StreamService.ts for this subroute. For me, they both belong together on the backend.

I think it would be great, if i could use tags for the service naming. I would then add the notifications tag for all these routes and it will create a notificationsService containing all routes which use the notifications tag. This way i would have more control over the generated api.

I know this is tricky and that the tags field in swagger is an array, this is why i would make it an option where the default is the path version of the service names.

Problem with optional params

This:

  async getAll(params?: {
    base: string;
    counter: string;
    id: number;
    description: string;
  })

Should become:

  async getAll(params?: {
    base?: string;
    counter?: string;
    id?: number;
    description?: string;
  })

Swagger Sample:

{
  "/api/v1/candle-import": {
    "get": {
      "consumes": [
        "application/json"
      ],
      "parameters": [
        {
          "in": "query",
          "name": "base",
          "required": false,
          "type": "string"
        },
        {
          "in": "query",
          "name": "counter",
          "required": false,
          "type": "string"
        },
        {
          "in": "query",
          "name": "id",
          "required": false,
          "type": "number"
        },
        {
          "in": "query",
          "name": "description",
          "required": false,
          "type": "string"
        }
      ],
      "produces": [
        "application/json"
      ],
      "responses": {
        "200": {
          "description": "",
          "schema": {
            "items": {
              "$ref": "#/definitions/CreateCandleImportResponse"
            },
            "type": "array"
          }
        }
      },
      "tags": [
        "candle-import"
      ]
    }
  }
}

Add repository information in package.json

The repository information is currently missing in the package.json. Therefore npmjs.com is not linking to github. One needs to search swaxios on github to find this repository

Use class properties

Integrate class properties by default.

Change:

async getAll(): Promise<Array<string>> {
  const resource = '/api/v1/strategy';
  const response = await this.apiClient.get<Array<string>>(resource);
  return response.data;
}

Into:

getAll = async (): Promise<Array<string>> => {
  const resource = '/api/v1/strategy';
  const response = await this.apiClient.get<Array<string>>(resource);
  return response.data;
}

Benefit:

It will allow us to pass functions like getAll around as props in the context of React.

Example:

<StringArraySelector
  getAll={new APIClient('').rest.api.v1.strategyService.getAll}
  label={'Strategy'}
  onSuccess={() => {}}
/>

Common parameters are not handled

Official docs:
https://swagger.io/docs/specification/describing-parameters/#common

My valid configuration:

paths:
  /posts/{id}:
    # This is considered as a request method then trows error
    parameters:
      - name: id
        in: path
        description: id
        required: true
        schema:
          type: integer
          format: int32
    get:
      # ...

Error on console:

TypeError: Cannot convert undefined or null to object
    at Function.entries (<anonymous>)
    at MethodGenerator.includesSuccessResponse (node_modules/swaxios/dist/generators/MethodGenerator.js:62:54)
    at new MethodGenerator (node_modules/swaxios/dist/generators/MethodGenerator.js:49:18)
    at new ResourceGenerator (node_modules/swaxios/dist/generators/ResourceGenerator.js:40:42)
    at node_modules/swaxios/dist/Swaxios.js:45:34
    at Generator.next (<anonymous>)
    at node_modules/swaxios/dist/Swaxios.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (node_modules/swaxios/dist/Swaxios.js:4:12)
    at exportServices (node_modules/swaxios/dist/Swaxios.js:34:12)
// new MethodGenerator (node_modules/swaxios/dist/generators/MethodGenerator.js:49:18)
const postFix = parameterMatch ? `By${StringUtil.camelCase(parameterMatch.splice(1), true)}` : 'All';
this.parameterMethod = this.operation.operationId || `${this.method}${postFix}`;
if (this.includesSuccessResponse(this.responses)) {
// where
//  - postFix: ById
//  - parameterMethod: propertiesById
//  - this.responses: undefined

// MethodGenerator.includesSuccessResponse (node_modules/swaxios/dist/generators/MethodGenerator.js:62:54
includesSuccessResponse(responses) {
    for (const [successCode, response] of Object.entries(responses)) { // <- response is undefined here

So, common parameters should be added to parameters as well, and if common parameters are defined it should be skipped when trying to process methods (operations).

Add support for "Bearer Authentication" in operations

Bearer Authentication can be enabled in Swagger when applying a security property.

swagger.json

{
 "/identity-providers/{id}": {
   "delete": {
     "consumes": ...,
     "parameters": ...,
     "produces": ...,
     "responses": ...,
     "security": [
       {
         "bearer": []
       }
     ]
   }
 }
}

Until we figure out how to internally store the access token (this.accessToken), we can add a parameter to functions which map authenticated endpoints, so that users can supply a callback which is responsible for returning the access token.

Suggestion

async deleteById(id: string, accessTokenCallback: () => Promise<string>): Promise<void> {
  const accessToken = await accessTokenCallback();
  const config: AxiosRequestConfig = {
    headers: {
      Authorization: `Bearer ${decodeURIComponent(accessToken)}`
    },
    method: 'delete',
    url: `/identity-providers/${id}`,
    withCredentials: true,
  };

  await this.apiClient.request(config);
}

Use ts-morph instead of Handlebars

ts-morph can create TypeScript with TypeScript. We should use it instead of using a template engine.

Pros

  • Cleaner TypeScript code
  • Staying in the TS world without reading external files
  • No more manual comment building
  • Handlebars is made for HTML

Cons

  • A lot of work for no visible output
  • There might be some TS expressions which are not supported by ts-morph yet (they need to be written manually then).

Add support for "Bearer Authentication" for the whole API

Bearer Authentication for the whole API can be enabled in Swagger when applying a security property.

swagger.json

{
 "paths": {
   // ...
 },
 "security": [
   {
     "Bearer": []
   }
 ],
 "swagger": "2.0",
}

Let's implement a general authorization setting (as suggested in #62 (comment)).

Suggestion

async deleteById(id: string): Promise<void> {
  const config: AxiosRequestConfig = {
    headers: {
      Authorization: this.config.accessToken,
    },
    method: 'delete',
    url: `/identity-providers/${id}`,
    withCredentials: true,
  };

  await this.apiClient.request(config);
}

Read "consumes" and write into "headers"

From the specification there can be a consumes property. We should read it and add it to the "headers" section within the AxiosRequestConfig object.

Example:

  "/api/v1/exchange/{id}": {
    "delete": {
      "consumes": [
        "application/json"
      ],
      // ...
  }

->

  const config: AxiosRequestConfig = {
    headers: { 'content-type': 'application/json' },
    // ...
  };

Possible operation ID duplicates

Since it's possible to add the same operation ID in two paths we should check that we don't create the same function twice in a class.

Support for "x-enumNames" in enum definitions

I found this StackOverflow question which wants to create an interface for Color based on the following JSON input:

{
  // ...
  "definitions": {
    "Color": {
      "description": "",
      "enum": [
        0,
        1,
        2
      ],
      "type": "integer",
      "x-enumNames": [
        "RED",
        "GREEN",
        "BLUE"
      ]
    }
  }
}

The expected result is:

export enum Color {
    RED = 0,
    GREEN = 1,
    BLUE = 2,
}

But swaxios 0.1.2 generates:

/* tslint:disable */

/**
 * This file was automatically generated by "Swaxios".
 * It should not be modified by hand.
 */

export type Color = number;

Complete input file:

{
  "consumes": [
    "application/json"
  ],
  "definitions": {
    "Bar": {
      "additionalProperties": false,
      "properties": {
        "A": {
          "type": "string"
        },
        "B": {
          "format": "int32",
          "type": "integer"
        },
        "Baz": {
          "$ref": "#/definitions/Baz"
        },
        "C": {
          "format": "date-time",
          "type": "string"
        }
      },
      "required": [
        "B",
        "C"
      ],
      "type": "object"
    },
    "Baz": {
      "additionalProperties": false,
      "properties": {
        "Color": {
          "$ref": "#/definitions/Color"
        },
        "D": {
          "format": "decimal",
          "type": "number"
        }
      },
      "required": [
        "D",
        "Color"
      ],
      "type": "object"
    },
    "Color": {
      "description": "",
      "enum": [
        0,
        1,
        2
      ],
      "type": "integer",
      "x-enumNames": [
        "RED",
        "GREEN",
        "BLUE"
      ]
    }
  },
  "info": {
    "title": "",
    "version": ""
  },
  "parameters": {},
  "paths": {
    "/api/Foo/GetBar": {
      "get": {
        "operationId": "Foo_GetBar",
        "parameters": [
          {
            "format": "int32",
            "in": "query",
            "name": "id",
            "required": true,
            "type": "integer",
            "x-nullable": false
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "schema": {
              "$ref": "#/definitions/Bar"
            },
            "x-nullable": true
          }
        },
        "tags": [
          "Foo"
        ]
      }
    },
    "/api/Foo/GetBarDescriptions": {
      "get": {
        "operationId": "Foo_GetBarDescriptions",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "schema": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "x-nullable": true
          }
        },
        "tags": [
          "Foo"
        ]
      }
    },
    "/api/Foo/SetBar": {
      "post": {
        "operationId": "Foo_SetBar",
        "parameters": [
          {
            "in": "body",
            "name": "value",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Bar"
            },
            "x-nullable": true
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "tags": [
          "Foo"
        ]
      }
    }
  },
  "produces": [
    "application/json"
  ],
  "responses": {},
  "schemes": [],
  "securityDefinitions": {},
  "swagger": "2.0",
  "x-generator": "NSwag v11.14.0.0 (NJsonSchema v9.10.24.0 (Newtonsoft.Json v9.0.0.0))"
}

The x-enumNames property is a custom property (indicated by the leading x-) but it seems to be very popular because it has been asked for in many other projects before:

Doc on enum flag:

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.