Введение
Начинаете новый Angular проект, но backend еще не готов? Не хотите ждать неделями, пока API будет разработан? В этом туториале вы создадите полноценное Todo приложение на Angular с API интеграцией за 15 минут — без единой строки backend кода.
✅ Что вы получите в конце:
- ✅ Рабочее Todo приложение с полным CRUD функционалом
- ✅ Angular 17+ с TypeScript (современный стек)
- ✅ Angular Services для работы с API
- ✅ HttpClient с RxJS Observables
- ✅ Dependency Injection
- ✅ Интеграция с Mock API (реальные HTTP запросы)
- ✅ Обработка ошибок и loading states
- ✅ Deploy на Vercel (готово к продакшену)
- ✅ Полный исходный код на GitHub
💡 Для кого этот туториал:
- Начинающие Angular разработчики: Изучите работу с API и сервисами
- Опытные разработчики: Ускорьте прототипирование с Mock API
- Frontend команды: Не ждите backend, начните прямо сейчас
- Студенты: Создайте портфолио проект за 15 минут
📋 План действий (15 минут)
- Что мы создадим (1 мин)
- Шаг 1: Setup проекта (2 мин)
- Шаг 2: Создание Mock API (3 мин)
- Шаг 3: Настройка HttpClient (1 мин)
- Шаг 4: Создание Angular Service (4 мин)
- Шаг 5: Создание компонентов (3 мин)
- Шаг 6: Error Handling и Interceptors (1 мин)
- Шаг 7: Deploy на Vercel (1 мин)
Что мы создадим 🎯
Мы создадим классическое Todo приложение с полноценным API. Это идеальный проект для изучения, так как он включает все основные операции:
| Функция | API Endpoint | Метод |
|---|---|---|
| Получить все задачи | GET /todos |
Read |
| Создать задачу | POST /todos |
Create |
| Обновить задачу | PUT /todos/:id |
Update |
| Удалить задачу | DELETE /todos/:id |
Delete |
Технологический стек
- Angular 17+ — мощный TypeScript фреймворк
- TypeScript — Типизация из коробки
- Angular CLI — Инструменты командной строки
- Angular Services — Бизнес-логика и работа с API
- HttpClient — Встроенный HTTP клиент
- RxJS — Reactive Extensions для работы с асинхронными данными
- Dependency Injection — Встроенная система DI
- LightBox API — Mock API платформа
Шаг 1: Setup проекта (2 минуты)
1 Установите Angular CLI (если еще не установлен)
# Глобальная установка Angular CLI
npm install -g @angular/cli
# Проверьте версию
ng version
2 Создайте Angular приложение
# Создаем новый проект
ng new todo-app
# Выберите:
# - Yes для routing (если хотите добавить позже)
# - CSS для стилей (или SCSS, если предпочитаете)
# - No для Standalone компонентов (используем модули)
# Переходим в директорию
cd todo-app
# Запускаем dev сервер (опционально, для проверки)
ng serve
3 Структура проекта
todo-app/
├── src/
│ ├── app/
│ │ ├── services/
│ │ │ └── todo.service.ts # Angular Service для API
│ │ ├── models/
│ │ │ └── todo.model.ts # TypeScript интерфейсы
│ │ ├── components/
│ │ │ ├── todo-list/
│ │ │ │ └── todo-list.component.ts
│ │ │ ├── todo-item/
│ │ │ │ └── todo-item.component.ts
│ │ │ └── add-todo/
│ │ │ └── add-todo.component.ts
│ │ ├── interceptors/
│ │ │ └── http-error.interceptor.ts
│ │ ├── app.component.ts
│ │ └── app.module.ts # Главный модуль
│ ├── environments/
│ │ ├── environment.ts # Production
│ │ └── environment.development.ts
│ ├── main.ts # Entry point
│ └── index.html
├── angular.json
└── package.json
Шаг 2: Создание Mock API (3 минуты)
1 Зарегистрируйтесь на LightBox API
Перейдите на lightboxapi.ru и создайте бесплатный аккаунт.
2 Создайте workspace
В dashboard создайте новый workspace с именем todo-app.
3 Настройте endpoints
Endpoint 1: GET /todos
{
"todos": [
{
"id": "1",
"title": "Изучить Angular Services",
"completed": false,
"createdAt": "2025-10-23T10:00:00Z"
},
{
"id": "2",
"title": "Интегрировать Mock API",
"completed": true,
"createdAt": "2025-10-23T09:00:00Z"
}
]
}
Endpoint 2: POST /todos
{
"id": "{randomUUID}",
"title": "{body.title}",
"completed": false,
"createdAt": "{$timestamp}"
}
Endpoint 3: PUT /todos/:id
{
"id": "{params.id}",
"title": "{body.title}",
"completed": "{body.completed}",
"createdAt": "{existing.createdAt}"
}
Endpoint 4: DELETE /todos/:id
{
"success": true,
"message": "Todo deleted"
}
Скопируйте URL вашего Mock API, например: https://lightboxapi.ru/your-workspace
Шаг 3: Настройка HttpClient (1 минута)
HttpClient — это встроенный Angular сервис для работы с HTTP запросами. Он использует RxJS Observables для асинхронной обработки.
1 Импортируйте HttpClientModule
Файл: src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { TodoListComponent } from './components/todo-list/todo-list.component';
import { TodoItemComponent } from './components/todo-item/todo-item.component';
import { AddTodoComponent } from './components/add-todo/add-todo.component';
@NgModule({
declarations: [
AppComponent,
TodoListComponent,
TodoItemComponent,
AddTodoComponent
],
imports: [
BrowserModule,
HttpClientModule // Добавляем HttpClient
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
2 Настройте environment variables
Файл: src/environments/environment.ts
export const environment = {
production: false,
apiUrl: 'https://lightboxapi.ru/your-workspace'
};
Файл: src/environments/environment.development.ts
export const environment = {
production: false,
apiUrl: 'https://lightboxapi.ru/your-workspace'
};
Шаг 4: Создание Angular Service (4 минуты)
Angular Services — это классы, которые содержат бизнес-логику и работу с API. Они инжектируются в компоненты через Dependency Injection.
1 Создайте TypeScript модели
Файл: src/app/models/todo.model.ts
export interface Todo {
id: string;
title: string;
completed: boolean;
createdAt: string;
}
export interface CreateTodoDto {
title: string;
}
export interface UpdateTodoDto {
title?: string;
completed?: boolean;
}
2 Создайте Angular Service
# Генерируем service через Angular CLI
ng generate service services/todo
Файл: src/app/services/todo.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { environment } from '../../environments/environment';
import { Todo, CreateTodoDto, UpdateTodoDto } from '../models/todo.model';
@Injectable({
providedIn: 'root' // Сервис доступен во всем приложении
})
export class TodoService {
private apiUrl = `${environment.apiUrl}/todos`;
constructor(private http: HttpClient) {}
// Получить все задачи
getAll(): Observable {
return this.http.get<{ todos: Todo[] }>(this.apiUrl).pipe(
map(response => response.todos),
catchError(this.handleError)
);
}
// Создать задачу
create(data: CreateTodoDto): Observable {
return this.http.post(this.apiUrl, data).pipe(
catchError(this.handleError)
);
}
// Обновить задачу
update(id: string, data: UpdateTodoDto): Observable {
return this.http.put(`${this.apiUrl}/${id}`, data).pipe(
catchError(this.handleError)
);
}
// Удалить задачу
delete(id: string): Observable {
return this.http.delete(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
// Переключить статус задачи
toggle(id: string, completed: boolean): Observable {
return this.update(id, { completed });
}
// Обработка ошибок
private handleError(error: HttpErrorResponse): Observable {
let errorMessage = 'Произошла ошибка';
if (error.error instanceof ErrorEvent) {
// Клиентская ошибка
errorMessage = `Ошибка: ${error.error.message}`;
} else {
// Серверная ошибка
errorMessage = `Код ошибки: ${error.status}, Сообщение: ${error.message}`;
}
console.error(errorMessage);
return throwError(() => new Error(errorMessage));
}
}
💡 Ключевые концепции Angular Service:
- @Injectable({ providedIn: 'root' }) — делает сервис singleton во всем приложении
- Dependency Injection — HttpClient инжектируется через конструктор
- RxJS Observables — все методы возвращают Observable
- RxJS операторы — map для трансформации, catchError для обработки ошибок
- TypeScript типы — полная типизация запросов и ответов
Шаг 5: Создание компонентов (3 минуты)
1 Главный компонент AppComponent
Файл: src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { TodoService } from './services/todo.service';
import { Todo, CreateTodoDto } from './models/todo.model';
Component(
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
)
export class AppComponent implements OnInit {
todos: Todo[] = [];
loading = false;
error: string | null = null;
constructor(private todoService: TodoService) {}
ngOnInit(): void {
this.loadTodos();
}
loadTodos(): void {
this.loading = true;
this.error = null;
this.todoService.getAll().subscribe({
next: (todos) => {
this.todos = todos;
this.loading = false;
},
error: (err) => {
this.error = err.message;
this.loading = false;
}
});
}
onTodoAdded(title: string): void {
const newTodo: CreateTodoDto = { title };
this.todoService.create(newTodo).subscribe({
next: (todo) => {
this.todos.push(todo);
},
error: (err) => {
this.error = err.message;
}
});
}
onTodoToggled(id: string): void {
const todo = this.todos.find(t => t.id === id);
if (todo) {
this.todoService.toggle(id, !todo.completed).subscribe({
next: (updated) => {
const index = this.todos.findIndex(t => t.id === id);
if (index !== -1) {
this.todos[index] = updated;
}
},
error: (err) => {
this.error = err.message;
}
});
}
}
onTodoDeleted(id: string): void {
this.todoService.delete(id).subscribe({
next: () => {
this.todos = this.todos.filter(t => t.id !== id);
},
error: (err) => {
this.error = err.message;
}
});
}
get todosCount(): number {
return this.todos.length;
}
get completedCount(): number {
return this.todos.filter(t => t.completed).length;
}
}
Файл: src/app/app.component.html
<div class="app">
<h1>Angular Todo App</h1>
<app-add-todo (todoAdded)="onTodoAdded($event)"></app-add-todo>
<div *ngIf="loading">Загрузка...</div>
<div *ngIf="error" class="error">{ error }</div>
<app-todo-list
[todos]="todos"
(todoToggled)="onTodoToggled($event)"
(todoDeleted)="onTodoDeleted($event)"
></app-todo-list>
<div class="stats">
Всего: { todosCount }, Выполнено: { completedCount }
</div>
</div>
2 Компонент TodoList
# Генерируем компонент
ng generate component components/todo-list
Файл: src/app/components/todo-list/todo-list.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { Todo } from '../../models/todo.model';
Component(
selector: 'app-todo-list',
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.css']
)
export class TodoListComponent {
@Input() todos: Todo[] = [];
@Output() todoToggled = new EventEmitter<string>();
@Output() todoDeleted = new EventEmitter<string>();
onToggle(id: string): void {
this.todoToggled.emit(id);
}
onDelete(id: string): void {
this.todoDeleted.emit(id);
}
}
Файл: src/app/components/todo-list/todo-list.component.html
<ul class="todo-list">
<app-todo-item
*ngFor="let todo of todos"
[todo]="todo"
(toggled)="onToggle($event)"
(deleted)="onDelete($event)"
></app-todo-item>
</ul>
3 Компонент AddTodo
ng generate component components/add-todo
Файл: src/app/components/add-todo/add-todo.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
Component(
selector: 'app-add-todo',
templateUrl: './add-todo.component.html',
styleUrls: ['./add-todo.component.css']
)
export class AddTodoComponent {
title = '';
@Output() todoAdded = new EventEmitter<string>();
onSubmit(): void {
if (this.title.trim()) {
this.todoAdded.emit(this.title);
this.title = '';
}
}
}
Файл: src/app/components/add-todo/add-todo.component.html
<form (ngSubmit)="onSubmit()" #todoForm="ngForm">
<input
[(ngModel)]="title"
name="title"
placeholder="Добавить задачу..."
required
/>
<button type="submit" [disabled]="!todoForm.valid">Добавить</button>
</form>
Важно: Добавьте FormsModule в app.module.ts для работы ngModel:
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
// ...
FormsModule
],
// ...
})
Шаг 6: Error Handling и Interceptors (1 минута)
HTTP Interceptors позволяют перехватывать и модифицировать HTTP запросы и ответы. Это идеально для обработки ошибок, добавления заголовков, логирования.
1 Создайте HTTP Error Interceptor
ng generate interceptor interceptors/http-error
Файл: src/app/interceptors/http-error.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest<unknown>,
next: HttpHandler
): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
let errorMessage = 'Произошла ошибка';
if (error.error instanceof ErrorEvent) {
errorMessage = `Ошибка: ${error.error.message}`;
} else {
errorMessage = `Ошибка ${error.status}: ${error.message}`;
}
console.error('HTTP Error:', errorMessage);
return throwError(() => new Error(errorMessage));
})
);
}
}
2 Зарегистрируйте Interceptor
Файл: src/app/app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpErrorInterceptor } from './interceptors/http-error.interceptor';
@NgModule({
// ...
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorInterceptor,
multi: true
}
],
// ...
})
Шаг 7: Deploy на Vercel (1 минута)
1 Соберите проект для production
# Сборка проекта
ng build --configuration production
# Проверьте, что dist/ папка создана
ls dist/todo-app/
2 Настройте Vercel
Создайте файл vercel.json в корне проекта:
{
"buildCommand": "ng build --configuration production",
"outputDirectory": "dist/todo-app",
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
],
"env": {
"API_URL": "https://lightboxapi.ru/your-workspace"
}
}
3 Deploy на Vercel
- Установите Vercel CLI:
npm i -g vercel - Выполните:
vercel - Следуйте инструкциям
- Или используйте GitHub интеграцию Vercel для автоматического деплоя
Результат 🎉
Поздравляем! Вы создали полноценное Angular приложение с API интеграцией за 15 минут. Приложение работает с реальными HTTP запросами к Mock API и готово к работе.
Что мы изучили:
- ✅ Angular Services и Dependency Injection
- ✅ HttpClient для HTTP запросов
- ✅ RxJS Observables и операторы
- ✅ TypeScript типизация в Angular
- ✅ Структура Angular компонентов
- ✅ HTTP Interceptors для обработки ошибок
- ✅ Интеграция с Mock API
- ✅ Deploy на Vercel
Продвинутые техники 🚀
1. RxJS операторы для оптимизации
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
// Поиск с debounce
search(term: string): Observable {
return this.http.get<Todo[]>(`${this.apiUrl}?search=${term}`).pipe(
debounceTime(300),
distinctUntilChanged()
);
}
2. Кэширование с RxJS
import { shareReplay } from 'rxjs/operators';
private todosCache$?: Observable;
getAll(): Observable {
if (!this.todosCache$) {
this.todosCache$ = this.http.get<{ todos: Todo[] }>(this.apiUrl).pipe(
map(response => response.todos),
shareReplay(1) // Кэшируем результат
);
}
return this.todosCache$;
}
3. Loading состояние с RxJS
import { BehaviorSubject } from 'rxjs';
private loading$ = new BehaviorSubject<boolean>(false);
getLoading(): Observable<boolean> {
return this.loading$.asObservable();
}
getAll(): Observable {
this.loading$.next(true);
return this.http.get<{ todos: Todo[] }>(this.apiUrl).pipe(
map(response => response.todos),
finalize(() => this.loading$.next(false))
);
}
Следующие шаги 🚀
- Добавьте роутинг: Используйте Angular Router для навигации
- Добавьте формы: Используйте Reactive Forms для валидации
- Добавьте состояние: Используйте NgRx для сложного state management
- Интегрируйте реальный API: Замените Mock API URL на production
- Добавьте тесты: Используйте Jasmine/Karma для unit тестов
- Оптимизируйте: Используйте OnPush change detection strategy
Создайте Mock API за 2 минуты
Не ждите backend — начните разработку Angular приложения прямо сейчас с LightBox API. Бесплатный старт для всех разработчиков.
Попробовать бесплатно →