Angular Example

Overview
This example demonstrates how to integrate ApiSorcery with Angular projects. Angular is a comprehensive platform for building web applications with TypeScript, providing powerful features like dependency injection, RxJS observables, and a robust CLI.
Features
- Type safety: Full TypeScript support with generated interfaces and types
- RxJS integration: Seamless integration with Angular's reactive programming patterns
- Dependency injection: Angular services for clean architecture
- Axios integration: Built-in support for Axios HTTP client with interceptors
- IntelliSense support: Full IDE support with auto-completion and type checking
- Tree shaking: Optimized bundle size with ES modules support
Quick Setup
1. Install ApiSorcery
bash
npm install -g autoapi2. Initialize Configuration
bash
autoapi init -l tsThis creates a .autoapirc.json configuration file:
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. Install Dependencies
bash
npm install axios
npm install -D @types/node4. Generate API Client
bash
autoapi generate5. Use in 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('Failed to fetch users:', error);
} finally {
this.loading = false;
}
}
}Angular Integration Patterns
Creating an Angular Service
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('Failed to fetch users:', 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())
);
}
}Using Service in Component
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();
}
}Component Template
html
<!-- user-list.component.html -->
<div class="user-list">
<div *ngIf="loading" class="loading">
<p>Loading...</p>
</div>
<ul *ngIf="!loading" class="users">
<li *ngFor="let user of users; trackBy: trackByUserId">
{{ user.name }}
</li>
</ul>
<button (click)="refresh()" [disabled]="loading">
Refresh
</button>
</div>Using with 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 : 'Failed to fetch users');
} finally {
this.loading.set(false);
}
}
}Best Practices
- Type Definitions: Leverage generated TypeScript interfaces for better type safety
- Angular Services: Encapsulate API calls in injectable services for reusability
- RxJS Operators: Use RxJS operators for data transformation and error handling
- Dependency Injection: Utilize Angular's DI system for clean architecture
- Unsubscribe Pattern: Always unsubscribe from observables to prevent memory leaks
- Error Handling: Implement proper error handling with Angular's error interceptors
- Environment Configuration: Use Angular environment files for different API endpoints
- Lazy Loading: Implement lazy loading for modules to optimize bundle size