Skip to content

Angular 示例

演示网站GitHub 源代码

概述

本示例演示如何将 ApiSorcery 与 Angular 项目集成。Angular 是一个使用 TypeScript 构建 Web 应用程序的综合平台,提供依赖注入、RxJS 可观察对象和强大的 CLI 等强大功能。

特性

  • 类型安全:完整的 TypeScript 支持,生成接口和类型
  • RxJS 集成:与 Angular 的响应式编程模式无缝集成
  • 依赖注入:使用 Angular 服务实现清晰的架构
  • Axios 集成:内置支持 Axios HTTP 客户端和拦截器
  • 智能提示支持:完整的 IDE 支持,包括自动完成和类型检查
  • Tree shaking:通过 ES 模块支持优化打包体积

快速开始

1. 安装 ApiSorcery

bash
npm install -g autoapi

2. 初始化配置

bash
autoapi init -l ts

这将创建一个 .autoapirc.json 配置文件:

json
{
  "application": {
    "language": "ts",
    "outputDir": "./src/app/api/auto"
  },
  "services": [
    {
      "code": "demo",
      "token": "72735b33815c4e5c9c2a924a8f4907ef",
      "version": 3,
      "enabled": true,
      "source": "https://your-api.com/swagger.json"
    }
  ]
}

3. 安装依赖

bash
npm install axios
npm install -D @types/node

4. 生成 API 客户端

bash
autoapi generate

5. 在 Angular 中使用

typescript
import { Component, OnInit } from '@angular/core';
import * as ApiUser from '@/app/api/auto/demo/ApiUser';
import type { User } from '@/app/api/auto/demo/model';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {
  users: User[] = [];
  loading = false;

  ngOnInit() {
    this.fetchUsers();
  }

  async fetchUsers() {
    this.loading = true;
    try {
      const res = await ApiUser.getUserPaged({
        pagination: {
          page: 1,
          limit: 10,
        },
      });
      this.users = res.results || [];
    } catch (error) {
      console.error('获取用户失败:', error);
    } finally {
      this.loading = false;
    }
  }
}

Angular 集成模式

创建 Angular 服务

typescript
// services/user.service.ts
import { Injectable } from '@angular/core';
import { Observable, from, BehaviorSubject } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
import * as ApiMain from '@/app/api/auto/demo/ApiMain';
import type { User } from '@/app/api/auto/demo/model';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private usersSubject = new BehaviorSubject<User[]>([]);
  private loadingSubject = new BehaviorSubject<boolean>(false);

  users$ = this.usersSubject.asObservable();
  loading$ = this.loadingSubject.asObservable();

  getUsers(): Observable<User[]> {
    this.loadingSubject.next(true);
    
    return from(ApiMain.getUsers()).pipe(
      map(response => response.data || []),
      tap(users => {
        this.usersSubject.next(users);
        this.loadingSubject.next(false);
      }),
      catchError(error => {
        this.loadingSubject.next(false);
        console.error('获取用户失败:', error);
        throw error;
      })
    );
  }

  getUserById(id: string): Observable<User> {
    return from(ApiMain.getUserById(id)).pipe(
      map(response => response.data)
    );
  }

  createUser(userData: Partial<User>): Observable<User> {
    return from(ApiMain.createUser(userData)).pipe(
      map(response => response.data),
      tap(() => this.getUsers().subscribe())
    );
  }
}

在组件中使用服务

typescript
// components/user-list/user-list.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { UserService } from '@/app/services/user.service';
import type { User } from '@/app/api/auto/main/model';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit, OnDestroy {
  users: User[] = [];
  loading = false;
  private destroy$ = new Subject<void>();

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.userService.users$
      .pipe(takeUntil(this.destroy$))
      .subscribe(users => this.users = users);

    this.userService.loading$
      .pipe(takeUntil(this.destroy$))
      .subscribe(loading => this.loading = loading);

    this.userService.getUsers().subscribe();
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }

  refresh() {
    this.userService.getUsers().subscribe();
  }
}

组件模板

html
<!-- user-list.component.html -->
<div class="user-list">
  <div *ngIf="loading" class="loading">
    <p>加载中...</p>
  </div>
  
  <ul *ngIf="!loading" class="users">
    <li *ngFor="let user of users; trackBy: trackByUserId">
      {{ user.name }}
    </li>
  </ul>
  
  <button (click)="refresh()" [disabled]="loading">
    刷新
  </button>
</div>

使用 Angular Signals(Angular 16+)

typescript
import { Component, OnInit, signal, computed } from '@angular/core';
import * as ApiMain from '@/app/api/auto/demo/ApiMain';
import type { User } from '@/app/api/auto/demo/model';

@Component({
  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  standalone: true
})
export class UserListComponent implements OnInit {
  users = signal<User[]>([]);
  loading = signal(false);
  error = signal<string | null>(null);
  
  userCount = computed(() => this.users().length);

  ngOnInit() {
    this.fetchUsers();
  }

  async fetchUsers() {
    this.loading.set(true);
    this.error.set(null);
    
    try {
      const response = await ApiMain.getUsers();
      this.users.set(response.data || []);
    } catch (err) {
      this.error.set(err instanceof Error ? err.message : '获取用户失败');
    } finally {
      this.loading.set(false);
    }
  }
}

最佳实践

  1. 类型定义:利用生成的 TypeScript 接口提高类型安全性
  2. Angular 服务:将 API 调用封装在可注入的服务中以实现可重用性
  3. RxJS 操作符:使用 RxJS 操作符进行数据转换和错误处理
  4. 依赖注入:利用 Angular 的 DI 系统实现清晰的架构
  5. 取消订阅模式:始终取消订阅可观察对象以防止内存泄漏
  6. 错误处理:使用 Angular 的错误拦截器实现适当的错误处理
  7. 环境配置:使用 Angular 环境文件配置不同的 API 端点
  8. 懒加载:实现模块的懒加载以优化打包体积