Skip to content

Feature/angular #944

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

Merged
merged 22 commits into from
Jan 28, 2022
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
484 changes: 22 additions & 462 deletions README.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const params = program
.version(pkg.version)
.requiredOption('-i, --input <value>', 'OpenAPI specification, can be a path, url or string content (required)')
.requiredOption('-o, --output <value>', 'Output directory (required)')
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, axios]', 'fetch')
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, axios, angular]', 'fetch')
.option('--name <value>', 'Custom client class name')
.option('--useOptions', 'Use options instead of arguments')
.option('--useUnionTypes', 'Use union types instead of enums')
Expand Down
84 changes: 84 additions & 0 deletions docs/angular-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Angular support

This tool allows you to generate a client based on the [`Angular HttpClient`](https://angular.io/guide/http).
The generated services are fully injectable and make use of the [RxJS](https://rxjs.dev/) Observer pattern.
If you want to generate the Angular based client then you can specify `--client angular` in the openapi call:

`openapi --input ./spec.json --output ./generated --client angular`

The Angular client has been tested with the following versions:

```
"@angular/common": "13.1.3",
"@angular/core": "13.1.3",
"rxjs": "7.5.2",
```

## Example

In the AppModule you can import the services and add them to the list of injectable services:

```typescript
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { OrganizationService } from './generated/services/OrganizationService';

@NgModule({
imports: [
BrowserModule,
HttpClientModule,
],
providers: [
OrganizationService,
],
bootstrap: [
AppComponent,
],
})
export class AppModule {}

platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
```

Inside the component you can inject the service and just use it as you would with any observable:

```typescript
import { Component } from '@angular/core';

import type { OrganizationService } from './generated/services/OrganizationService';

@Component({
selector: 'app-root',
template: `<div>Angular is ready</div>`,
})
export class AppComponent {
constructor(private readonly organizationService: OrganizationService) {

// Make a call
this.organizationService
.createOrganization({
name: 'OrgName',
description: 'OrgDescription',
})
.subscribe(organization => {
console.log(organization);
});

// Or even map result and retry on error
this.organizationService
.getOrganizations()
.pipe(
map(organizations => organizations[0]),
retryWhen(error => error)
)
.subscribe(organization => {
console.log(organization);
});
}
}
```
37 changes: 37 additions & 0 deletions docs/arguments-vs-object-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Arguments vs. Object style

**Flag:** `--useOptions`

There's no [named parameter](https://en.wikipedia.org/wiki/Named_parameter) in JavaScript or TypeScript, because of
that, we offer the flag `--useOptions` to generate code in two different styles.

**Argument style:**

```typescript
const createUser = (name: string, password: string, type?: string, address?: string) => {
// ...
};

// Usage
createUser('Jack', '123456', undefined, 'NY US');
```

**Object style:**

```typescript
const createUser = ({ name, password, type, address }: {
name: string,
password: string,
type?: string
address?: string
}) => {
// ...
};

// Usage
createUser({
name: 'Jack',
password: '123456',
address: 'NY US'
});
```
24 changes: 24 additions & 0 deletions docs/authorization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Authorization

The OpenAPI generator supports Bearer Token authorization. In order to enable the sending
of tokens in each request you can set the token using the global OpenAPI configuration:

```typescript
import { OpenAPI } from './generated';

OpenAPI.TOKEN = 'some-bearer-token';
```

Alternatively, we also support an async method that provides the token for each request.
You can simply assign this method to the same `TOKEN `property in the global OpenAPI object.

```typescript
import { OpenAPI } from './generated';

const getToken = async () => {
// Some code that requests a token...
return 'SOME_TOKEN';
};

OpenAPI.TOKEN = getToken;
```
18 changes: 18 additions & 0 deletions docs/axios-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Axios support

This tool allows you to generate a client based on the [`Axios`](https://www.npmjs.com/package/axios) client.
The advantage of the Axios client is that it works in both Node.js and Browser based environments.
If you want to generate the Axios based client then you can specify `--client axios` in the openapi call:

`openapi --input ./spec.json --output ./generated --client axios`

The only downside is that this client needs some additional dependencies to work (due to the missing FormData
classes in Node.js).

```
npm install axios --save-dev
npm install [email protected] --save-dev
```

In order to compile the project and resolve the imports, you will need to enable the `allowSyntheticDefaultImports`
in your `tsconfig.json` file.
19 changes: 19 additions & 0 deletions docs/babel-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Babel support

If you use enums inside your models / definitions then those enums are by default inside a namespace with the same name
as your model. This is called declaration merging. However, the [@babel/plugin-transform-typescript](https://babeljs.io/docs/en/babel-plugin-transform-typescript)
does not support these namespaces, so if you are using babel in your project please use the `--useUnionTypes` flag
to generate union types instead of traditional enums. More info can be found here: [Enums vs. Union Types](#enums-vs-union-types---useuniontypes).

**Note:** If you are using Babel 7 and Typescript 3.8 (or higher) then you should enable the `onlyRemoveTypeImports` to
ignore any 'type only' imports, see https://babeljs.io/docs/en/babel-preset-typescript#onlyremovetypeimports for more info

```javascript
module.exports = {
presets: [
['@babel/preset-typescript', {
onlyRemoveTypeImports: true,
}],
],
};
```
61 changes: 61 additions & 0 deletions docs/basic-usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Basic usage

```
$ openapi --help

Usage: openapi [options]

Options:
-V, --version output the version number
-i, --input <value> OpenAPI specification, can be a path, url or string content (required)
-o, --output <value> Output directory (required)
-c, --client <value> HTTP client to generate [fetch, xhr, node, axios, angular] (default: "fetch")
--name <value> Custom client class name
--useOptions Use options instead of arguments
--useUnionTypes Use union types instead of enums
--exportCore <value> Write core files to disk (default: true)
--exportServices <value> Write services to disk (default: true)
--exportModels <value> Write models to disk (default: true)
--exportSchemas <value> Write schemas to disk (default: false)
--indent <value> Indentation options [4, 2, tab] (default: "5")
--postfix <value> Service name postfix (default: "Service")
--request <value> Path to custom request file
-h, --help display help for command

Examples
$ openapi --input ./spec.json --output ./generated
```

## Example

**package.json**
```json
{
"scripts": {
"generate": "openapi --input ./spec.json --output ./generated"
}
}
```

**NPX**

```
npx openapi-typescript-codegen --input ./spec.json --output ./generated
```

**Node.js**

```javascript
const OpenAPI = require('openapi-typescript-codegen');

OpenAPI.generate({
input: './spec.json',
output: './generated',
});

// Or by providing the content of the spec directly 🚀
OpenAPI.generate({
input: require('./spec.json'),
output: './generated',
});
```
27 changes: 27 additions & 0 deletions docs/client-instances.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Client instances

**Flag:** `--name`

The OpenAPI generator allows creation of client instances to support the multiple backend services use case.
The generated client uses an instance of the server configuration and not the global `OpenAPI` constant.
To generate a client instance, set a custom name to the client class, use `--name` option.

```
openapi --input ./spec.json --output ./generated ---name AppClient
```

The generated client will be exported from the `index` file and can be used as shown below:

```typescript
// Create the client instance with server and authentication details
const appClient = new AppClient({
BASE: 'http://server-host.com',
TOKEN: '1234',
});

// Use the client instance to make the API call
const response = await appClient.organizations.createOrganization({
name: 'OrgName',
description: 'OrgDescription',
});
```
47 changes: 47 additions & 0 deletions docs/custom-enums.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Enum with custom names and descriptions

You can use `x-enum-varnames` and `x-enum-descriptions` in your spec to generate enum with custom names and descriptions.
It's not in official [spec](https://github.com/OAI/OpenAPI-Specification/issues/681) yet. But it's a supported extension
that can help developers use more meaningful enumerators.

```json
{
"EnumWithStrings": {
"description": "This is a simple enum with strings",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"Success",
"Warning",
"Error"
],
"x-enum-descriptions": [
"Used when the status of something is successful",
"Used when the status of something has a warning",
"Used when the status of something has an error"
]
}
}
```

Generated code:

```typescript
enum EnumWithStrings {
/*
* Used when the status of something is successful
*/
Success = 0,
/*
* Used when the status of something has a warning
*/
Waring = 1,
/*
* Used when the status of something has an error
*/
Error = 2,
}
```
54 changes: 54 additions & 0 deletions docs/enum-vs-union-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Enums vs. Union types

**Flag:** `--useUnionTypes`

The OpenAPI spec allows you to define [enums](https://swagger.io/docs/specification/data-models/enums/) inside the
data model. By default, we convert these enums definitions to [TypeScript enums](https://www.typescriptlang.org/docs/handbook/enums.html).
However, these enums are merged inside the namespace of the model, this is unsupported by Babel, [see docs](https://babeljs.io/docs/en/babel-plugin-transform-typescript#impartial-namespace-support).
Because we also want to support projects that use Babel [@babel/plugin-transform-typescript](https://babeljs.io/docs/en/babel-plugin-transform-typescript),
we offer the flag `--useUnionTypes` to generate [union types](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#union-types)
instead of the traditional enums. The difference can be seen below:

**Enums:**

```typescript
// Model
export type Order = {
id?: number;
quantity?: number;
status?: Order.status;
};

export namespace Order {
export enum status {
PLACED = 'placed',
APPROVED = 'approved',
DELIVERED = 'delivered',
}
}

// Usage
const order: Order = {
id: 1,
quantity: 40,
status: Order.status.PLACED,
};
```

**Union Types:**

```typescript
// Model
export type Order = {
id?: number;
quantity?: number;
status?: 'placed' | 'approved' | 'delivered';
};

// Usage
const order: Order = {
id: 1,
quantity: 40,
status: 'placed',
};
```
Loading