ЛЕКЦ 07

API Дизайн ба RESTful Үйлчилгээ

ЛЕКЦ 07: API ДИЗАЙН БА RESTFUL ҮЙЛЧИЛГЭЭ (API Design & RESTful Services)

Хичээлийн зорилго: API-ийн ойлголт, REST архитектурын зарчмууд, HTTP протокол, RESTful API дизайн, Spring Boot ашиглан API хөгжүүлэх, аюулгүй байдал, баримт бичиг зэргийг Java жишээнүүдтэйгээр эзэмшүүлэх.

Хамрах хүрээ: API тодорхойлолт, REST зарчмууд, HTTP методууд, Status Code, URI дизайн, Request/Response, JSON, Spring Boot REST Controller, DTO Pattern, Validation, Exception Handling, Authentication/Authorization, API Versioning, Documentation (OpenAPI/Swagger), HATEOAS, Rate Limiting.



ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)

1.1 API гэж юу вэ?

API (Application Programming Interface) — Програм хоорондын харилцааны гэрээ (contract). Нэг програм нөгөө програмтай мэдээлэл солилцох, функц дуудах боломжийг олгоно.

💡 Зүйрлэл: Зоогийн газрын цэс (меню) шиг — та гал тогооны өрөөнд ороод хоол хийхгүй. ЦЭСНЭЭС сонгоод, зөөгч (API) дамжуулж, хоолоо авна. API = Цэс + Зөөгч.

API-ийн төрлүүд:

#ТөрөлТайлбарЖишээ
1Web API (REST)HTTP-ээр дамжуулан ажилладагGitHub API, Google Maps API
2Library APIСангийн функцүүдJava Collections API
3OS APIҮйлдлийн системийн интерфейсWindows API, POSIX
4Database APIМэдээллийн сантай харилцахJDBC, JPA
5GraphQLQuery-д суурилсанGitHub GraphQL API
6gRPCӨндөр гүйцэтгэлтэй RPCGoogle-ийн дотоод үйлчилгээ

API яагаад чухал вэ?

┌──────────────┐     API      ┌──────────────┐
│   Frontend   │◄────────────►│   Backend    │
│  (React,     │   HTTP/JSON  │  (Spring     │
│   Mobile)    │              │   Boot)      │
└──────────────┘              └──────┬───────┘
                                     │ API
                              ┌──────▼───────┐
                              │  Database    │
                              │  (PostgreSQL)│
                              └──────────────┘

┌──────────────┐     API      ┌──────────────┐
│  Гадаад      │◄────────────►│  Манай       │
│  Систем      │              │  Систем      │
│  (Банк,      │              │              │
│   SMS)       │              │              │
└──────────────┘              └──────────────┘
  • Frontend ↔ Backend хоорондын гүүр
  • Мобайл апп ↔ Сервер хоорондын гүүр
  • Гадаад систем (төлбөр, SMS, газрын зураг) ашиглах
  • Microservice архитектурт үйлчилгээ хоорондын харилцаа

1.2 REST гэж юу вэ?

REST (Representational State Transfer) — Roy Fielding 2000 онд докторын дипломын ажилдаа тодорхойлсон архитектурын хэв маяг (architectural style). Web-ийн стандарт протокол (HTTP) дээр суурилсан.

💡 Зүйрлэл: Шуудангийн систем шиг — Хаяг (URL) + Үйлдэл (GET/POST) + Агуулга (JSON) = Мэдээлэл солилцох.

REST-ийн 6 зарчим:

#ЗарчимАнглиТайлбар
1Клиент-СерверClient-ServerКлиент ба сервер тусдаа, бие даасан
2ТөлөвгүйStatelessСервер клиентийн төлөв хадгалахгүй — хүсэлт бүр бие даасан
3Кэшлэх боломжтойCacheableХариу кэшлэгдэж болно (хурд нэмэх)
4Нэгдмэл интерфейсUniform InterfaceURL, HTTP метод, JSON — нэгдсэн дүрмээр
5Давхарт системLayered SystemКлиент завсрын давхарга (load balancer, proxy) мэдэхгүй
6Код дуудахCode on Demand (заавал биш)Сервер клиент руу код (JS) илгээж болно

Stateless (Төлөвгүй) — Яагаад чухал вэ?

// ❌ STATEFUL — Сервер хэрэглэгчийн төлөв хадгална
Хүсэлт 1: "Нэвтрэх" → Сервер: session["user"] = "Бат"
Хүсэлт 2: "Захиалга" → Сервер: session["user"]-аас "Бат" гэж олно
⚠️ Асуудал: Сервер 2 руу шилжвэл session алга!

// ✅ STATELESS — Хүсэлт бүрт бүх мэдээлэл агуулагдана
Хүсэлт 1: "Нэвтрэх" → Сервер: JWT Token буцаана
Хүсэлт 2: "Захиалга" + Token → Сервер: Token-аас "Бат" гэж мэднэ
✅ Аль ч сервер руу очсон ажиллана (scale хялбар)

1.3 HTTP протокол

1.3.1 HTTP методууд (Verbs)

МетодЗорилгоИдемпотентАюулгүйCRUD
GETНөөц авах (уншиx)✅ Тийм✅ ТиймRead
POSTШинэ нөөц үүсгэх❌ Үгүй❌ ҮгүйCreate
PUTНөөц бүхлээр нь солих✅ Тийм❌ ҮгүйUpdate (бүхэлд)
PATCHНөөцийн зарим хэсгийг өөрчлөх❌ Үгүй❌ ҮгүйUpdate (хэсэг)
DELETEНөөц устгах✅ Тийм❌ ҮгүйDelete

Идемпотент = Олон удаа дуудсан ч үр дүн ижил.

  • GET /students/1 → Хэдэн удаа дуудсан ч ижил оюутан буцна.
  • DELETE /students/1 → Нэг удаа устгана, дахин дуудвал "олдсонгүй" (үр дүн ижил — устгагдсан).
  • POST /students → Дуудах бүрт ШИНЭ оюутан үүснэ (идемпотент БИШ).

1.3.2 HTTP Status Code (Хариуны код)

КодБүлэгТайлбарЖишээ
200✅ SuccessАмжилттайGET хариу
201✅ CreatedШинэ нөөц үүссэнPOST амжилттай
204✅ No ContentАмжилттай, хариу хоосонDELETE амжилттай
400❌ Bad RequestБуруу хүсэлтValidation алдаа
401❌ UnauthorizedНэвтрэлт шаардлагатайToken байхгүй
403❌ ForbiddenХандах эрхгүйЭрх хүрэлцэхгүй
404❌ Not FoundНөөц олдсонгүйID буруу
405❌ Method Not AllowedМетод зөвшөөрөгдөхгүйGET-ийн оронд PUT
409❌ ConflictЗөрчилДавхардсан бүртгэл
422❌ Unprocessable EntityБоловсруулж чадахгүйЛогик алдаа
429❌ Too Many RequestsХэт олон хүсэлтRate limit
500💥 Internal Server ErrorСерверийн дотоод алдааBug, crash
502💥 Bad GatewayGateway алдааBackend унтарсан
503💥 Service UnavailableҮйлчилгээ боломжгүйЗасвартай
Бүлэглэлт:
1xx = Мэдээлэл (Informational)
2xx = Амжилттай (Success)        ← Бүгд сайн
3xx = Чиглүүлэлт (Redirection)
4xx = Клиентийн алдаа (Client Error) ← Хэрэглэгч буруу
5xx = Серверийн алдаа (Server Error) ← Сервер буруу

1.3.3 HTTP Headers

HeaderТөрөлТайлбар
Content-TypeRequest/ResponseАгуулгын формат: application/json
AcceptRequestКлиент хүссэн формат: application/json
AuthorizationRequestНэвтрэлтийн мэдээлэл: Bearer <token>
Cache-ControlResponseКэш тохиргоо: no-cache, max-age=3600
LocationResponseШинэ нөөцийн URL (201 Created-д)
X-Request-IdCustomХүсэлтийн давтагдашгүй ID (tracking)

1.4 RESTful URI дизайн

1.4.1 Нөөц (Resource) төвтэй дизайн

🔑 REST-ийн гол зарчим: URI нь НӨӨЦ (noun)-ийг илэрхийлнэ, ҮЙЛДЭЛ (verb)-ийг БИШ. Үйлдлийг HTTP метод илэрхийлнэ.

// ❌ БУРУУ — URI-д үйлдэл (verb) байна
GET /getStudents
GET /getAllStudents
POST /createStudent
PUT /updateStudent/1
DELETE /deleteStudent/1

// ✅ ЗӨӨВ — URI нь нөөцийг илэрхийлж, HTTP метод нь үйлдлийг
GET    /students          → Бүх оюутан авах
GET    /students/1        → ID=1 оюутан авах
POST   /students          → Шинэ оюутан үүсгэх
PUT    /students/1        → ID=1 оюутныг бүхэлд нь шинэчлэх
PATCH  /students/1        → ID=1 оюутны зарим хэсгийг өөрчлөх
DELETE /students/1        → ID=1 оюутныг устгах

1.4.2 URI дизайны дүрмүүд

#ДүрэмЗөвБуруу
1Олон тоо ашиглах/students/student
2Жижиг үсэг/students/Students
3Зураас (-) ашиглах/course-enrollments/courseEnrollments
4Төгсгөлд / байхгүй/students/students/
5Файлын өргөтгөлгүй/students/students.json
6Шатлалтай/students/1/courses/getStudentCourses?id=1
7Үйлдэл (verb) байхгүйPOST /studentsPOST /createStudent

1.4.3 Шатлалтай нөөц (Nested Resources)

// Оюутны хичээлүүд
GET /students/1/courses              → ID=1 оюутны бүх хичээл
GET /students/1/courses/5            → ID=1 оюутны 5-р хичээл
POST /students/1/courses             → ID=1 оюутанд хичээл нэмэх

// Хичээлийн оюутнууд
GET /courses/5/students              → 5-р хичээлийн бүх оюутан

// Гүнзгий шатлал (2-оос илүү зайлсхий)
GET /universities/1/departments/3/students  → Хэт гүнзгий ❌
GET /departments/3/students                 → Илүү энгийн ✅

1.4.4 Шүүлт, Эрэмбэ, Хуудаслалт (Filtering, Sorting, Pagination)

// Шүүлтүүр (Filter) — Query Parameter ашиглах
GET /students?status=active                  → Идэвхтэй оюутнууд
GET /students?gpa_min=3.5&status=active      → GPA >= 3.5 + идэвхтэй

// Эрэмбэ (Sort)
GET /students?sort=name&order=asc            → Нэрээр А→Я
GET /students?sort=gpa&order=desc            → GPA-аар буурах

// Хуудаслалт (Pagination)
GET /students?page=1&size=20                 → 1-р хуудас, 20 бичлэг
GET /students?page=2&size=20                 → 2-р хуудас

// Бүгд хамтдаа
GET /students?status=active&sort=gpa&order=desc&page=1&size=10

1.5 Request & Response формат

1.5.1 JSON формат

JSON (JavaScript Object Notation) — API-ийн хамгийн түгээмэл өгөгдлийн формат.

// Нэг оюутан (Response)
{
    "id": 1,
    "name": "Батболд",
    "email": "batbold@example.com",
    "gpa": 3.75,
    "status": "ACTIVE",
    "enrolledAt": "2024-09-01"
}

// Олон оюутан (Хуудаслалттай Response)
{
    "content": [
        {"id": 1, "name": "Батболд", "gpa": 3.75},
        {"id": 2, "name": "Сарангэрэл", "gpa": 3.90}
    ],
    "page": 1,
    "size": 20,
    "totalElements": 150,
    "totalPages": 8
}

1.5.2 Request Body (POST/PUT)

// POST /students — Шинэ оюутан үүсгэх
{
    "name": "Батболд",
    "email": "batbold@example.com",
    "gpa": 3.75
}

// PUT /students/1 — Оюутныг бүхэлд нь шинэчлэх
{
    "name": "Батболд Дорж",
    "email": "batbold.dorj@example.com",
    "gpa": 3.80
}

// PATCH /students/1 — Зөвхөн email шинэчлэх
{
    "email": "new.email@example.com"
}

1.5.3 Алдааны Response (Error Response)

// 400 Bad Request
{
    "status": 400,
    "error": "Bad Request",
    "message": "Validation алдаа",
    "details": [
        {"field": "email", "message": "Имэйл формат буруу"},
        {"field": "name", "message": "Нэр хоосон байж болохгүй"}
    ],
    "timestamp": "2024-09-15T10:30:00",
    "path": "/api/v1/students"
}

// 404 Not Found
{
    "status": 404,
    "error": "Not Found",
    "message": "ID=999 оюутан олдсонгүй",
    "timestamp": "2024-09-15T10:30:00",
    "path": "/api/v1/students/999"
}

1.6 Spring Boot REST API хөгжүүлэлт

1.6.1 Давхарт архитектур (Layered Architecture)

┌────────────────────────────────────────────┐
│            Client (Browser, Mobile)        │
└──────────────────┬─────────────────────────┘
                   │ HTTP Request/Response
┌──────────────────▼─────────────────────────┐
│        Controller Layer (REST API)         │
│   @RestController — Хүсэлт хүлээн авах    │
└──────────────────┬─────────────────────────┘
                   │ DTO ↔ Entity
┌──────────────────▼─────────────────────────┐
│          Service Layer (Бизнес логик)      │
│   @Service — Бизнес дүрэм, логик          │
└──────────────────┬─────────────────────────┘
                   │ Entity
┌──────────────────▼─────────────────────────┐
│        Repository Layer (Мэдээллийн сан)   │
│   @Repository / JpaRepository              │
└──────────────────┬─────────────────────────┘
                   │ SQL
┌──────────────────▼─────────────────────────┐
│              Database (PostgreSQL)          │
└────────────────────────────────────────────┘

1.6.2 Entity (Мэдээллийн сангийн хүснэгт)

@Entity
@Table(name = "students")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private Double gpa;

    @Enumerated(EnumType.STRING)
    private StudentStatus status = StudentStatus.ACTIVE;

    @Column(name = "enrolled_at")
    private LocalDate enrolledAt;

    // Constructor, Getter, Setter
}

public enum StudentStatus {
    ACTIVE, INACTIVE, GRADUATED, SUSPENDED
}

1.6.3 DTO (Data Transfer Object)

🔑 DTO яагаад хэрэгтэй? Entity-г шууд API-аар буцаахгүй — нууц мэдээлэл (password), шаардлагагүй талбар (internal ID) задрах эрсдэлтэй.

// Request DTO — Клиентээс ирэх
public record StudentCreateRequest(
    @NotBlank(message = "Нэр хоосон байж болохгүй")
    String name,

    @Email(message = "Имэйл формат буруу")
    @NotBlank(message = "Имэйл хоосон байж болохгүй")
    String email,

    @Min(value = 0, message = "GPA 0-аас бага байж болохгүй")
    @Max(value = 4, message = "GPA 4-аас их байж болохгүй")
    Double gpa
) {}

// Response DTO — Клиент руу буцах
public record StudentResponse(
    Long id,
    String name,
    String email,
    Double gpa,
    String status,
    LocalDate enrolledAt
) {
    public static StudentResponse from(Student student) {
        return new StudentResponse(
            student.getId(),
            student.getName(),
            student.getEmail(),
            student.getGpa(),
            student.getStatus().name(),
            student.getEnrolledAt()
        );
    }
}

1.6.4 Repository

public interface StudentRepository extends JpaRepository<Student, Long> {

    Optional<Student> findByEmail(String email);

    List<Student> findByStatus(StudentStatus status);

    @Query("SELECT s FROM Student s WHERE s.gpa >= :minGpa")
    List<Student> findByMinGpa(@Param("minGpa") Double minGpa);

    boolean existsByEmail(String email);
}

1.6.5 Service

@Service
@RequiredArgsConstructor
public class StudentService {

    private final StudentRepository repository;

    public List<StudentResponse> findAll() {
        return repository.findAll().stream()
            .map(StudentResponse::from)
            .toList();
    }

    public StudentResponse findById(Long id) {
        Student student = repository.findById(id)
            .orElseThrow(() -> new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            ));
        return StudentResponse.from(student);
    }

    @Transactional
    public StudentResponse create(StudentCreateRequest request) {
        if (repository.existsByEmail(request.email())) {
            throw new DuplicateEmailException(
                "'" + request.email() + "' имэйл бүртгэлтэй байна"
            );
        }

        Student student = new Student();
        student.setName(request.name());
        student.setEmail(request.email());
        student.setGpa(request.gpa());
        student.setEnrolledAt(LocalDate.now());

        Student saved = repository.save(student);
        return StudentResponse.from(saved);
    }

    @Transactional
    public StudentResponse update(Long id, StudentCreateRequest request) {
        Student student = repository.findById(id)
            .orElseThrow(() -> new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            ));

        student.setName(request.name());
        student.setEmail(request.email());
        student.setGpa(request.gpa());

        Student saved = repository.save(student);
        return StudentResponse.from(saved);
    }

    @Transactional
    public void delete(Long id) {
        if (!repository.existsById(id)) {
            throw new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            );
        }
        repository.deleteById(id);
    }
}

1.6.6 Controller

@RestController
@RequestMapping("/api/v1/students")
@RequiredArgsConstructor
public class StudentController {

    private final StudentService studentService;

    @GetMapping
    public ResponseEntity<List<StudentResponse>> findAll() {
        return ResponseEntity.ok(studentService.findAll());
    }

    @GetMapping("/{id}")
    public ResponseEntity<StudentResponse> findById(@PathVariable Long id) {
        return ResponseEntity.ok(studentService.findById(id));
    }

    @PostMapping
    public ResponseEntity<StudentResponse> create(
            @Valid @RequestBody StudentCreateRequest request) {
        StudentResponse created = studentService.create(request);
        URI location = URI.create("/api/v1/students/" + created.id());
        return ResponseEntity.created(location).body(created);
    }

    @PutMapping("/{id}")
    public ResponseEntity<StudentResponse> update(
            @PathVariable Long id,
            @Valid @RequestBody StudentCreateRequest request) {
        return ResponseEntity.ok(studentService.update(id, request));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        studentService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

1.6.7 Global Exception Handler

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(StudentNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(StudentNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.NOT_FOUND.value(),
            "Not Found",
            ex.getMessage(),
            LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(DuplicateEmailException.class)
    public ResponseEntity<ErrorResponse> handleDuplicate(DuplicateEmailException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.CONFLICT.value(),
            "Conflict",
            ex.getMessage(),
            LocalDateTime.now()
        );
        return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(
            MethodArgumentNotValidException ex) {
        List<String> details = ex.getBindingResult().getFieldErrors().stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage())
            .toList();

        ErrorResponse error = new ErrorResponse(
            HttpStatus.BAD_REQUEST.value(),
            "Validation Error",
            "Оролтын өгөгдөл буруу",
            LocalDateTime.now(),
            details
        );
        return ResponseEntity.badRequest().body(error);
    }
}

public record ErrorResponse(
    int status,
    String error,
    String message,
    LocalDateTime timestamp,
    List<String> details
) {
    public ErrorResponse(int status, String error, String message,
                         LocalDateTime timestamp) {
        this(status, error, message, timestamp, null);
    }
}

1.7 API хувилбар (Versioning)

Яагаад API хувилбар хэрэгтэй вэ?

API өөрчлөгдөхөд хуучин клиентүүд ЭВДРЭХГҮЙ байх → Хувилбараар удирдах.

#АргаЖишээДавуу талСул тал
1URI Path/api/v1/studentsЭнгийн, тодорхойURI өөрчлөгдөнө
2Query Param/api/students?version=1Уян хатанМартаж болно
3HeaderAccept: application/vnd.api.v1+jsonURI цэвэрХүндрэлтэй
4Media TypeContent-Type: application/vnd.api.v1+jsonСтандартНарийн

Зөвлөмж: URI Path (/api/v1/...) нь хамгийн энгийн, түгээмэл, ойлгомжтой → Эхлэгчдэд тохиромжтой.


1.8 Authentication & Authorization

1.8.1 Ялгаа

ОйлголтТайлбарЗүйрлэл
Authentication (AuthN)Хэн бэ? НэвтрэлтПаспорт шалгах
Authorization (AuthZ)Юу хийж болох вэ? ЭрхVIP билет шалгах

1.8.2 JWT (JSON Web Token)

┌─────────┐   1. Login (username, password)    ┌─────────┐
│         │ ──────────────────────────────────► │         │
│ Client  │   2. JWT Token                      │ Server  │
│         │ ◄────────────────────────────────── │         │
│         │   3. Request + Authorization:       │         │
│         │      Bearer <token>                 │         │
│         │ ──────────────────────────────────► │         │
│         │   4. Response (200 OK)              │         │
│         │ ◄────────────────────────────────── │         │
└─────────┘                                     └─────────┘

JWT бүтэц:

Header.Payload.Signature

// Header
{
    "alg": "HS256",
    "typ": "JWT"
}

// Payload (Claims)
{
    "sub": "batbold@example.com",
    "name": "Батболд",
    "role": "STUDENT",
    "iat": 1694736000,
    "exp": 1694822400
}

// Signature
HMACSHA256(base64(header) + "." + base64(payload), secret)

1.8.3 API Key vs OAuth 2.0 vs JWT

АргаТохиромжтойТайлбар
API KeyЭнгийн интеграциНэг түлхүүр — хялбар, гэхдээ хязгаарлагдмал
JWTStateless authToken-д мэдээлэл агуулагдана, session-гүй
OAuth 2.0Гуравдагч этгээдийн нэвтрэлт"Google-ээр нэвтрэх" зэрэг

1.9 API Баримт бичиг (Documentation)

OpenAPI / Swagger

OpenAPI — API-ийн тодорхойлолтын стандарт формат (YAML/JSON). Swagger UI — OpenAPI-с автоматаар интерактив баримт бичиг үүсгэнэ.

# openapi.yaml жишээ (хялбаршуулсан)
openapi: 3.0.3
info:
  title: Student API
  version: 1.0.0
paths:
  /api/v1/students:
    get:
      summary: Бүх оюутан авах
      responses:
        '200':
          description: Амжилттай
    post:
      summary: Шинэ оюутан үүсгэх
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StudentCreateRequest'
      responses:
        '201':
          description: Үүсгэгдсэн

Spring Boot + Swagger тохиргоо:

// build.gradle
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'

// application.yml
springdoc:
  api-docs:
    path: /api-docs
  swagger-ui:
    path: /swagger-ui.html

// Controller дээр annotation
@Operation(summary = "Бүх оюутан авах", description = "Бүх оюутны жагсаалт")
@ApiResponse(responseCode = "200", description = "Амжилттай")
@GetMapping
public ResponseEntity<List<StudentResponse>> findAll() { ... }

Swagger UI: http://localhost:8080/swagger-ui.html — Браузераас API-г шууд туршиж болно.


1.10 REST API шилдэг туршлагууд (Best Practices)

#ЗарчимТайлбар
1Нөөц төвтэй URI/students (noun), /createStudent биш (verb)
2HTTP метод зөв ашиглахGET = Унших, POST = Үүсгэх, PUT = Шинэчлэх, DELETE = Устгах
3Status Code зөв буцаах200, 201, 204, 400, 404, 500 — Зорилгод тохирсон
4Хувилбар ашиглах/api/v1/students
5Validation хийх@Valid, @NotBlank, @Email
6Нэгдмэл алдааны форматErrorResponse DTO
7ХуудаслалтОлон бичлэгт page, size parameter
8DTO ашиглахEntity шууд буцаахгүй
9HTTPS ашиглахМэдээлэл шифрлэгдэнэ
10Rate LimitingХэт олон хүсэлтээс хамгаалах
11Баримт бичигSwagger / OpenAPI
12IdempotencyPUT, DELETE идемпотент байх

1.11 REST vs GraphQL vs gRPC

ШинжRESTGraphQLgRPC
ПротоколHTTP/JSONHTTP/JSONHTTP/2 + Protobuf
ХүсэлтОлон endpointНэг endpoint, queryService method
Over-fetchingБайж болноБайхгүй (хэрэгтэйгээ сонгоно)Байхгүй
Under-fetchingБайж болноБайхгүйБайхгүй
СуралцахадХялбарДундХүнд
ХурдСайнСайнХамгийн хурдан
ТохиромжтойCRUD API, вэбУян хатан query, mobileMicroservice, real-time

Over-fetching = Хэрэгцээнээс илүү мэдээлэл ирэх (жишээ: зөвхөн нэр хэрэгтэй, бүх талбар ирэх). Under-fetching = Нэг хүсэлтээр хүрэлцэхгүй, нэмэлт хүсэлт шаардлагатай.


1.12 HATEOAS

HATEOAS (Hypermedia As The Engine Of Application State) — REST-ийн дээд түвшний зарчим. Response дотор дараагийн боломжит үйлдлүүдийн холбоос агуулна.

// HATEOAS Response жишээ
{
    "id": 1,
    "name": "Батболд",
    "email": "batbold@example.com",
    "gpa": 3.75,
    "_links": {
        "self": {"href": "/api/v1/students/1"},
        "courses": {"href": "/api/v1/students/1/courses"},
        "update": {"href": "/api/v1/students/1", "method": "PUT"},
        "delete": {"href": "/api/v1/students/1", "method": "DELETE"}
    }
}

💡 Зүйрлэл: Вэб хуудас дахь "Дараах", "Өмнөх", "Засах", "Устгах" товчлуурууд шиг — API-ийн хариунд дараа юу хийж болохыг заасан холбоосууд.



ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)

#Англи нэр томьёоМонгол утгаДэлгэрэнгүй тайлбар
1APIПрограмын интерфейсApplication Programming Interface — Програм хоорондын харилцааны гэрээ.
2RESTТөлөөлөлт шилжүүлэлтRepresentational State Transfer — HTTP дээр суурилсан архитектурын хэв маяг.
3RESTfulREST зарчимтайREST зарчмуудыг баримталсан API.
4HTTPГипертекст дамжуулах протоколHyperText Transfer Protocol — Web-ийн суурь протокол.
5HTTPSАюулгүй HTTPHTTP + TLS/SSL шифрлэлт.
6EndpointТөгсгөлийн цэгAPI-ийн тодорхой URL + HTTP метод хослол.
7URI / URLНөөцийн хаягUniform Resource Identifier — Нөөцийн байршил.
8HTTP MethodHTTP аргаGET, POST, PUT, PATCH, DELETE — Үйлдлийн төрөл.
9Status CodeХариуны код200, 404, 500 зэрэг — Хүсэлтийн үр дүнгийн код.
10JSONJSON форматJavaScript Object Notation — Өгөгдлийн формат.
11RequestХүсэлтКлиентээс сервер рүү илгээх мэдээлэл.
12ResponseХариуСерверээс клиент рүү буцах мэдээлэл.
13Request BodyХүсэлтийн биеPOST/PUT хүсэлтийн JSON өгөгдөл.
14HeaderТолгойHTTP хүсэлт/хариуны нэмэлт мэдээлэл.
15Query ParameterАсуулгын параметрURL-д ?key=value хэлбэрээр дамжуулах.
16Path VariableЗам хувьсагчURL-д /students/{id} хэлбэрээр дамжуулах.
17StatelessТөлөвгүйСервер клиентийн төлөв хадгалахгүй.
18IdempotentИдемпотентОлон удаа дуудсан ч үр дүн ижил.
19CRUDCRUD үйлдлүүдCreate, Read, Update, Delete — Суурь үйлдлүүд.
20DTOМэдээлэл дамжуулах объектData Transfer Object — API-ийн хүсэлт/хариуны объект.
21EntityНэгжМэдээллийн сангийн хүснэгтийг илэрхийлэх Java класс.
22RepositoryМэдээллийн агуулахМэдээллийн сантай харилцах давхарга.
23ServiceҮйлчилгээний давхаргаБизнес логик хариуцах давхарга.
24ControllerХянагчHTTP хүсэлт хүлээн авах, хариу буцаах давхарга.
25JWTJSON Web TokenStateless нэвтрэлтийн токен.
26AuthenticationНэвтрэлтХэн бэ? — Хэрэглэгчийг таних.
27AuthorizationЭрх зүйЮу хийж болох вэ? — Хандах эрх шалгах.
28OAuth 2.0OAuth протоколГуравдагч этгээдээр нэвтрэх стандарт.
29API KeyAPI түлхүүрAPI-д хандах нууц түлхүүр.
30Rate LimitingХурд хязгаарлалтХэт олон хүсэлтээс хамгаалах механизм.
31PaginationХуудаслалтОлон бичлэгийг хуудас хуудсаар буцаах.
32FilteringШүүлтБичлэгийг нөхцөлөөр шүүх.
33SortingЭрэмбэлэлтБичлэгийг талбараар эрэмбэлэх.
34Swagger / OpenAPIAPI баримт бичигAPI-ийн интерактив баримт бичгийн стандарт.
35HATEOASГипермедиаHypermedia As The Engine Of Application State.
36GraphQLГрафQLQuery-д суурилсан API хэл.
37gRPCgRPCGoogle-ийн өндөр хурдтай RPC framework.
38PayloadАчааХүсэлт/хариуны гол өгөгдөл.
39ValidationБаталгаажуулалтОролтын өгөгдлийг шалгах.
40SerializationЦуваачлалОбъектыг JSON/XML формат руу хөрвүүлэх.


ХЭСЭГ 3: ЛАБОРАТОРИ БА ПРАКТИК ЗААВАР (Labs & Step-by-Step Guide)

3.1 Лабораторийн зорилго

Энэ лабораторид та Spring Boot ашиглан RESTful API бүтээж, бодит дадлага хийнэ:

  1. Spring Boot төсөл үүсгэх
  2. CRUD REST API хөгжүүлэх (Entity, DTO, Repository, Service, Controller)
  3. Validation ба Exception Handling
  4. Swagger/OpenAPI баримт бичиг

Хэл: Java 17+ | Framework: Spring Boot 3.x | IDE: Eclipse IDE


3.2 Лаб 1: Spring Boot төсөл үүсгэх

Алхам 1: Spring Initializr ашиглах

https://start.spring.io руу орж:

ТохиргооУтга
ProjectMaven
LanguageJava
Spring Boot3.2.x
Groupcom.example
Artifactstudent-api
PackagingJar
Java17

Алхам 2: Dependency нэмэх

<!-- pom.xml -->
<dependencies>
    <!-- Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- JPA + Database -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- H2 Database (хөгжүүлэлтийн орчинд) -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Validation -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <!-- Swagger/OpenAPI -->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        <version>2.3.0</version>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- Test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Алхам 3: application.yml тохиргоо

# src/main/resources/application.yml
server:
  port: 8080

spring:
  datasource:
    url: jdbc:h2:mem:studentdb
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
      path: /h2-console
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true

springdoc:
  swagger-ui:
    path: /swagger-ui.html

Алхам 4: Ажиллуулах

./mvnw spring-boot:run

Шалгах:

  • http://localhost:8080/h2-console → H2 Database console
  • http://localhost:8080/swagger-ui.html → Swagger UI

3.3 Лаб 2: CRUD REST API хөгжүүлэх

Алхам 1: Entity үүсгэх

// src/main/java/com/example/studentapi/entity/Student.java
package com.example.studentapi.entity;

import jakarta.persistence.*;
import java.time.LocalDate;

@Entity
@Table(name = "students")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private Double gpa;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private StudentStatus status = StudentStatus.ACTIVE;

    @Column(name = "enrolled_at")
    private LocalDate enrolledAt = LocalDate.now();

    public Student() {}

    public Student(String name, String email, Double gpa) {
        this.name = name;
        this.email = email;
        this.gpa = gpa;
    }

    // Getter, Setter методууд
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    public Double getGpa() { return gpa; }
    public void setGpa(Double gpa) { this.gpa = gpa; }
    public StudentStatus getStatus() { return status; }
    public void setStatus(StudentStatus status) { this.status = status; }
    public LocalDate getEnrolledAt() { return enrolledAt; }
    public void setEnrolledAt(LocalDate enrolledAt) { this.enrolledAt = enrolledAt; }
}
// src/main/java/com/example/studentapi/entity/StudentStatus.java
package com.example.studentapi.entity;

public enum StudentStatus {
    ACTIVE, INACTIVE, GRADUATED, SUSPENDED
}

Алхам 2: DTO үүсгэх

// src/main/java/com/example/studentapi/dto/StudentCreateRequest.java
package com.example.studentapi.dto;

import jakarta.validation.constraints.*;

public record StudentCreateRequest(
    @NotBlank(message = "Нэр хоосон байж болохгүй")
    @Size(min = 2, max = 100, message = "Нэр 2-100 тэмдэгт байх ёстой")
    String name,

    @NotBlank(message = "Имэйл хоосон байж болохгүй")
    @Email(message = "Имэйл формат буруу")
    String email,

    @NotNull(message = "GPA заавал оруулна")
    @Min(value = 0, message = "GPA 0-аас бага байж болохгүй")
    @Max(value = 4, message = "GPA 4-аас их байж болохгүй")
    Double gpa
) {}
// src/main/java/com/example/studentapi/dto/StudentResponse.java
package com.example.studentapi.dto;

import com.example.studentapi.entity.Student;
import java.time.LocalDate;

public record StudentResponse(
    Long id,
    String name,
    String email,
    Double gpa,
    String status,
    LocalDate enrolledAt
) {
    public static StudentResponse from(Student student) {
        return new StudentResponse(
            student.getId(),
            student.getName(),
            student.getEmail(),
            student.getGpa(),
            student.getStatus().name(),
            student.getEnrolledAt()
        );
    }
}

Алхам 3: Repository үүсгэх

// src/main/java/com/example/studentapi/repository/StudentRepository.java
package com.example.studentapi.repository;

import com.example.studentapi.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

public interface StudentRepository extends JpaRepository<Student, Long> {
    Optional<Student> findByEmail(String email);
    boolean existsByEmail(String email);
}

Алхам 4: Custom Exception үүсгэх

// src/main/java/com/example/studentapi/exception/StudentNotFoundException.java
package com.example.studentapi.exception;

public class StudentNotFoundException extends RuntimeException {
    public StudentNotFoundException(String message) {
        super(message);
    }
}
// src/main/java/com/example/studentapi/exception/DuplicateEmailException.java
package com.example.studentapi.exception;

public class DuplicateEmailException extends RuntimeException {
    public DuplicateEmailException(String message) {
        super(message);
    }
}

Алхам 5: Service үүсгэх

// src/main/java/com/example/studentapi/service/StudentService.java
package com.example.studentapi.service;

import com.example.studentapi.dto.*;
import com.example.studentapi.entity.Student;
import com.example.studentapi.exception.*;
import com.example.studentapi.repository.StudentRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
public class StudentService {

    private final StudentRepository repository;

    public StudentService(StudentRepository repository) {
        this.repository = repository;
    }

    public List<StudentResponse> findAll() {
        return repository.findAll().stream()
            .map(StudentResponse::from)
            .toList();
    }

    public StudentResponse findById(Long id) {
        Student student = repository.findById(id)
            .orElseThrow(() -> new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            ));
        return StudentResponse.from(student);
    }

    @Transactional
    public StudentResponse create(StudentCreateRequest request) {
        if (repository.existsByEmail(request.email())) {
            throw new DuplicateEmailException(
                "'" + request.email() + "' имэйл бүртгэлтэй байна"
            );
        }
        Student student = new Student(
            request.name(), request.email(), request.gpa()
        );
        Student saved = repository.save(student);
        return StudentResponse.from(saved);
    }

    @Transactional
    public StudentResponse update(Long id, StudentCreateRequest request) {
        Student student = repository.findById(id)
            .orElseThrow(() -> new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            ));
        student.setName(request.name());
        student.setEmail(request.email());
        student.setGpa(request.gpa());
        Student saved = repository.save(student);
        return StudentResponse.from(saved);
    }

    @Transactional
    public void delete(Long id) {
        if (!repository.existsById(id)) {
            throw new StudentNotFoundException(
                "ID=" + id + " оюутан олдсонгүй"
            );
        }
        repository.deleteById(id);
    }
}

Алхам 6: Controller үүсгэх

// src/main/java/com/example/studentapi/controller/StudentController.java
package com.example.studentapi.controller;

import com.example.studentapi.dto.*;
import com.example.studentapi.service.StudentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/api/v1/students")
@Tag(name = "Student API", description = "Оюутны CRUD API")
public class StudentController {

    private final StudentService studentService;

    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }

    @GetMapping
    @Operation(summary = "Бүх оюутан авах")
    public ResponseEntity<List<StudentResponse>> findAll() {
        return ResponseEntity.ok(studentService.findAll());
    }

    @GetMapping("/{id}")
    @Operation(summary = "ID-аар оюутан авах")
    public ResponseEntity<StudentResponse> findById(@PathVariable Long id) {
        return ResponseEntity.ok(studentService.findById(id));
    }

    @PostMapping
    @Operation(summary = "Шинэ оюутан үүсгэх")
    public ResponseEntity<StudentResponse> create(
            @Valid @RequestBody StudentCreateRequest request) {
        StudentResponse created = studentService.create(request);
        URI location = URI.create("/api/v1/students/" + created.id());
        return ResponseEntity.created(location).body(created);
    }

    @PutMapping("/{id}")
    @Operation(summary = "Оюутны мэдээлэл шинэчлэх")
    public ResponseEntity<StudentResponse> update(
            @PathVariable Long id,
            @Valid @RequestBody StudentCreateRequest request) {
        return ResponseEntity.ok(studentService.update(id, request));
    }

    @DeleteMapping("/{id}")
    @Operation(summary = "Оюутан устгах")
    public ResponseEntity<Void> delete(@PathVariable Long id) {
        studentService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

Алхам 7: Global Exception Handler

// src/main/java/com/example/studentapi/exception/GlobalExceptionHandler.java
package com.example.studentapi.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(StudentNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleNotFound(StudentNotFoundException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.NOT_FOUND.value(), "Not Found",
            ex.getMessage(), LocalDateTime.now(), null
        );
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
    }

    @ExceptionHandler(DuplicateEmailException.class)
    public ResponseEntity<ErrorResponse> handleDuplicate(DuplicateEmailException ex) {
        ErrorResponse error = new ErrorResponse(
            HttpStatus.CONFLICT.value(), "Conflict",
            ex.getMessage(), LocalDateTime.now(), null
        );
        return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidation(
            MethodArgumentNotValidException ex) {
        List<String> details = ex.getBindingResult().getFieldErrors().stream()
            .map(e -> e.getField() + ": " + e.getDefaultMessage())
            .toList();
        ErrorResponse error = new ErrorResponse(
            HttpStatus.BAD_REQUEST.value(), "Validation Error",
            "Оролтын өгөгдөл буруу", LocalDateTime.now(), details
        );
        return ResponseEntity.badRequest().body(error);
    }
}
// src/main/java/com/example/studentapi/exception/ErrorResponse.java
package com.example.studentapi.exception;

import java.time.LocalDateTime;
import java.util.List;

public record ErrorResponse(
    int status,
    String error,
    String message,
    LocalDateTime timestamp,
    List<String> details
) {}

3.4 Лаб 3: API тестлэх (cURL / Swagger)

cURL ашиглан тестлэх:

# 1. Шинэ оюутан үүсгэх (POST)
curl -X POST http://localhost:8080/api/v1/students \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Батболд",
    "email": "batbold@example.com",
    "gpa": 3.75
  }'
# Хариу: 201 Created + StudentResponse JSON

# 2. Бүх оюутан авах (GET)
curl http://localhost:8080/api/v1/students
# Хариу: 200 OK + List<StudentResponse>

# 3. ID-аар оюутан авах (GET)
curl http://localhost:8080/api/v1/students/1
# Хариу: 200 OK + StudentResponse

# 4. Оюутны мэдээлэл шинэчлэх (PUT)
curl -X PUT http://localhost:8080/api/v1/students/1 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Батболд Дорж",
    "email": "batbold.dorj@example.com",
    "gpa": 3.80
  }'
# Хариу: 200 OK + Шинэчлэгдсэн StudentResponse

# 5. Оюутан устгах (DELETE)
curl -X DELETE http://localhost:8080/api/v1/students/1
# Хариу: 204 No Content

# 6. Validation алдаа тестлэх
curl -X POST http://localhost:8080/api/v1/students \
  -H "Content-Type: application/json" \
  -d '{
    "name": "",
    "email": "буруу-имэйл",
    "gpa": 5.0
  }'
# Хариу: 400 Bad Request + Validation алдааны жагсаалт

# 7. Олдохгүй оюутан тестлэх
curl http://localhost:8080/api/v1/students/999
# Хариу: 404 Not Found + "ID=999 оюутан олдсонгүй"

Swagger UI ашиглан тестлэх:

  1. http://localhost:8080/swagger-ui.html нээх
  2. "Student API" бүлгийг дарж нээх
  3. "Try it out" товч дарах
  4. Параметр оруулж "Execute" дарах
  5. Response шалгах

3.5 Лаб 4: Хуудаслалт ба Шүүлт нэмэх

Controller-д хуудаслалт нэмэх:

// StudentController.java — findAll методыг шинэчлэх
@GetMapping
@Operation(summary = "Оюутны жагсаалт (хуудаслалттай)")
public ResponseEntity<Page<StudentResponse>> findAll(
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size,
        @RequestParam(defaultValue = "id") String sortBy,
        @RequestParam(defaultValue = "asc") String order) {

    Sort sort = order.equalsIgnoreCase("desc")
        ? Sort.by(sortBy).descending()
        : Sort.by(sortBy).ascending();

    Page<StudentResponse> result = studentService.findAll(
        PageRequest.of(page, size, sort)
    );
    return ResponseEntity.ok(result);
}
// StudentService.java — findAll методыг шинэчлэх
public Page<StudentResponse> findAll(Pageable pageable) {
    return repository.findAll(pageable)
        .map(StudentResponse::from);
}

Тестлэх:

# 1-р хуудас, 5 бичлэг, GPA-аар буурах
curl "http://localhost:8080/api/v1/students?page=0&size=5&sortBy=gpa&order=desc"


ХЭСЭГ 4: ШАЛГАЛТЫН АСУУЛТ (Knowledge Check — 100 тест)

Тест 1

API гэж юу вэ?

  • A) Зөвхөн вэб хуудас
  • B) Програм хоорондын харилцааны гэрээ (интерфейс)
  • C) Мэдээллийн сан
  • D) Зөвхөн мобайл апп

Зөв хариулт: B

Тайлбар: API = Application Programming Interface. Нэг програм нөгөө програмтай мэдээлэл солилцох, функц дуудах боломжийг олгодог гэрээ.

Тест 2

REST гэдэг юуны товчлол вэ?

  • A) Remote Execution System Transfer
  • B) Representational State Transfer
  • C) Request-Server Technology
  • D) Resource Extraction Standard Tool

Зөв хариулт: B

Тайлбар: REST = Representational State Transfer. Roy Fielding 2000 онд тодорхойлсон, HTTP дээр суурилсан архитектурын хэв маяг.

Тест 3

REST-ийн "Stateless" зарчим юу гэсэн утгатай вэ?

  • A) Сервер клиентийн session хадгална
  • B) Хүсэлт бүр бие даасан — сервер клиентийн төлөв хадгалахгүй
  • C) Клиент сервертэй холбогдохгүй
  • D) Зөвхөн GET хүсэлт ашиглах

Зөв хариулт: B

Тайлбар: Stateless = Хүсэлт бүрт шаардлагатай бүх мэдээлэл (token, параметр) агуулагдана. Сервер session хадгалахгүй → Scale хялбар, аль ч сервер хариулж чадна.

Тест 4

HTTP GET метод юу хийдэг вэ?

  • A) Нөөц үүсгэх
  • B) Нөөц устгах
  • C) Нөөц уншиx (авах)
  • D) Нөөц шинэчлэх

Зөв хариулт: C

Тайлбар: GET = Read. Серверээс мэдээлэл авах. Сервер дээрх өгөгдлийг ӨӨРЧЛӨХГҮЙ (safe + idempotent).

Тест 5

HTTP POST метод юу хийдэг вэ?

  • A) Нөөц уншиx
  • B) Шинэ нөөц ҮҮСГЭХ
  • C) Нөөц устгах
  • D) Нөөцийн зарим хэсгийг өөрчлөх

Зөв хариулт: B

Тайлбар: POST = Create. Шинэ нөөц үүсгэнэ. Дуудах бүрт ШИНЭ нөөц үүснэ → Идемпотент БИШ.

Тест 6

HTTP PUT ба PATCH-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) PUT = нөөцийг БҮХЭЛД нь солих, PATCH = зарим ХЭСГИЙГ өөрчлөх
  • C) PUT = устгах, PATCH = үүсгэх
  • D) PUT = уншиx, PATCH = устгах

Зөв хариулт: B

Тайлбар: PUT = Бүх талбарыг илгээж, бүхлээр солих. PATCH = Зөвхөн өөрчлөх талбаруудыг илгээх. Жишээ: Зөвхөн email солих → PATCH.

Тест 7

"Идемпотент" (Idempotent) гэж юу вэ?

  • A) Хурдан ажиллах
  • B) Олон удаа дуудсан ч үр дүн ИЖИЛ байх
  • C) Зөвхөн нэг удаа дуудах
  • D) Алдаагүй байх

Зөв хариулт: B

Тайлбар: GET, PUT, DELETE = Идемпотент (10 удаа дуудсан ч ижил үр дүн). POST = Идемпотент БИШ (дуудах бүрт шинэ нөөц үүснэ).

Тест 8

HTTP 200 status code юу гэсэн утгатай вэ?

  • A) Шинэ нөөц үүссэн
  • B) Амжилттай (OK)
  • C) Нөөц олдсонгүй
  • D) Серверийн алдаа

Зөв хариулт: B

Тайлбар: 200 OK = Хүсэлт амжилттай. GET хүсэлтийн хариуд хамгийн түгээмэл.

Тест 9

HTTP 201 status code юу гэсэн утгатай вэ?

  • A) Хүсэлт амжилттай
  • B) Шинэ нөөц амжилттай ҮҮССЭН (Created)
  • C) Агуулга хоосон
  • D) Чиглүүлэлт

Зөв хариулт: B

Тайлбар: 201 Created = POST хүсэлтийн амжилттай хариу. Шинэ нөөц үүссэн, Location header-т шинэ URL буцна.

Тест 10

HTTP 404 status code юу гэсэн утгатай вэ?

  • A) Серверийн алдаа
  • B) Нэвтрэлт шаардлагатай
  • C) Нөөц ОЛДСОНГҮЙ (Not Found)
  • D) Буруу хүсэлт

Зөв хариулт: C

Тайлбар: 404 Not Found = Хүсэлт илгээсэн нөөц серверт олдсонгүй. Жишээ: /students/999 — ID=999 оюутан байхгүй.

Тест 11

HTTP 500 status code юу гэсэн утгатай вэ?

  • A) Клиентийн алдаа
  • B) Нөөц олдсонгүй
  • C) Серверийн ДОТООД алдаа (Internal Server Error)
  • D) Хэт олон хүсэлт

Зөв хариулт: C

Тайлбар: 500 = Серверт bug, crash, exception гарсан. 5xx = Серверийн буруу. 4xx = Клиентийн буруу.

Тест 12

HTTP 401 ба 403-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) 401 = Нэвтрэлт ШААРДЛАГАТАЙ (хэн бэ мэдэхгүй), 403 = Нэвтэрсэн ч ЭРХ ХҮРЭЛЦЭХГҮЙ
  • C) 401 = Олдсонгүй, 403 = Серверийн алдаа
  • D) 401 = Шинэ нөөц, 403 = Устгагдсан

Зөв хариулт: B

Тайлбар: 401 Unauthorized = "Чи хэн бэ?" (Token байхгүй/буруу). 403 Forbidden = "Чи хэн бэ мэднэ, гэхдээ эрхгүй" (Student → Admin хуудас).

Тест 13

RESTful URI дизайнд аль нь ЗӨӨВ вэ?

  • A) GET /getStudents
  • B) GET /students
  • C) GET /getAllStudentsList
  • D) GET /fetchStudentData

Зөв хариулт: B

Тайлбар: REST = Нөөц (noun) төвтэй URI. /students = Нөөц. Үйлдлийг HTTP метод (GET) илэрхийлнэ. URI-д verb (get, fetch, create) байхгүй.

Тест 14

URI-д олон тоо ашиглах дүрэм аль нь зөв вэ?

  • A) /student (ганц тоо)
  • B) /students (олон тоо)
  • C) /student_list
  • D) /studentData

Зөв хариулт: B

Тайлбар: REST стандарт: Нөөцийн нэрийг ОЛОН ТООГООР бичих. /students = Оюутнуудын цуглуулга. /students/1 = Нэг оюутан.

Тест 15

Шатлалтай нөөцийн (nested resource) зөв жишээ аль нь вэ?

  • A) GET /getStudentCourses?studentId=1
  • B) GET /students/1/courses
  • C) GET /courses-of-student-1
  • D) GET /studentCourses/1

Зөв хариулт: B

Тайлбар: /students/1/courses = ID=1 оюутны хичээлүүд. Шатлал → Нөөцийн хамаарлыг тодорхой илэрхийлнэ. 2-3 түвшнээс илүү гүнзгий зайлсхий.

Тест 16

Query Parameter юунд ашигладаг вэ?

  • A) Нөөц үүсгэх
  • B) Шүүлт, эрэмбэ, хуудаслалт — ?status=active&page=1&size=10
  • C) Нөөц устгах
  • D) Нэвтрэх

Зөв хариулт: B

Тайлбар: Query Parameter (?key=value) = Нөөцийн цуглуулгыг шүүх, эрэмбэлэх, хуудаслах. Нөөцийн ID-г PATH-аар (/students/1), шүүлтийг QUERY-ээр.

Тест 17

JSON формат дахь зөв бичиглэл аль нь вэ?

  • A) {name: "Бат"}
  • B) {"name": "Бат"}
  • C) {name = "Бат"}
  • D) <name>Бат</name>

Зөв хариулт: B

Тайлбар: JSON = Түлхүүр (key) ЗААВАЛ давхар хашилттай (""). {"name": "Бат"} = Зөв. {name: "Бат"} = JavaScript-д зөв, JSON-д БУРУУ.

Тест 18

DTO (Data Transfer Object) яагаад хэрэгтэй вэ?

  • A) Шаардлагагүй
  • B) Entity-г шууд API-аар буцаахгүй — нууц мэдээлэл задрахаас хамгаалах, API гэрээг тусгаарлах
  • C) Зөвхөн тест бичихэд
  • D) Зөвхөн формат солиход

Зөв хариулт: B

Тайлбар: Entity шууд буцаавал: password задарна, internal ID ил гарна, Entity өөрчлөхөд API эвдэрнэ. DTO = API-ийн гэрээг Entity-ээс тусгаарлах.

Тест 19

Spring Boot-д @RestController annotation юу хийдэг вэ?

  • A) Мэдээллийн сан холбох
  • B) HTTP хүсэлт хүлээн авч, JSON хариу буцаах REST Controller зарлах
  • C) Тест ажиллуулах
  • D) Security тохируулах

Зөв хариулт: B

Тайлбар: @RestController = @Controller + @ResponseBody. Бүх метод автоматаар JSON/XML буцаана. HTML view биш, DATA буцаана.

Тест 20

@GetMapping("/{id}") дахь {id} юу вэ?

  • A) Query Parameter
  • B) Path Variable — URL-ийн хэсэг болж дамжуулагдах хувьсагч
  • C) Header
  • D) Request Body

Зөв хариулт: B

Тайлбар: {id} = Path Variable. /students/1 дахь 1 = id утга. @PathVariable Long id ашиглан авна.

Тест 21

@RequestBody annotation юу хийдэг вэ?

  • A) URL-аас параметр авах
  • B) HTTP хүсэлтийн BODY дахь JSON-ийг Java объект руу хөрвүүлэх
  • C) Header авах
  • D) Cookie авах

Зөв хариулт: B

Тайлбар: @RequestBody StudentCreateRequest request = Клиентийн илгээсэн JSON → Java объект (deserialization). POST, PUT хүсэлтэд ашиглана.

Тест 22

ResponseEntity юу хийдэг вэ?

  • A) Зөвхөн JSON буцаах
  • B) HTTP Status Code + Header + Body-г бүрэн хянах боломжийг олгох
  • C) Зөвхөн алдаа буцаах
  • D) Зөвхөн string буцаах

Зөв хариулт: B

Тайлбар: ResponseEntity.created(location).body(dto) = 201 + Location header + Body. Status code, header, body-г бүгдийг удирдах боломжтой.

Тест 23

@Valid annotation юу хийдэг вэ?

  • A) Код компайлдах
  • B) DTO дахь validation annotation-уудыг (@NotBlank, @Email г.м.) идэвхжүүлж шалгах
  • C) Тест ажиллуулах
  • D) Лог бичих

Зөв хариулт: B

Тайлбар: @Valid @RequestBody StudentCreateRequest request@NotBlank, @Email, @Min, @Max зэрэг шалгалтууд ажиллана. Буруу бол 400 Bad Request.

Тест 24

@RestControllerAdvice юу хийдэг вэ?

  • A) Controller үүсгэх
  • B) Бүх Controller-ийн Exception-ийг НЭГДМЭЛ газар зохицуулах (Global Exception Handler)
  • C) Тест бичих
  • D) Security тохируулах

Зөв хариулт: B

Тайлбар: @RestControllerAdvice + @ExceptionHandler = Бүх алдааг нэг газар зохицуулж, нэгдмэл формат (ErrorResponse) буцаана.

Тест 25

JWT (JSON Web Token) юу вэ?

  • A) Мэдээллийн сан
  • B) Stateless нэвтрэлтийн токен — Header.Payload.Signature бүтэцтэй
  • C) API баримт бичиг
  • D) Тестийн framework

Зөв хариулт: B

Тайлбар: JWT = Нэвтрэлтийн мэдээлэл (хэн бэ, ямар эрхтэй, хэзээ дуусах) агуулсан, гарын үсэгтэй токен. Authorization: Bearer <token> header-ээр дамжуулна.

Тест 26

Authentication ба Authorization-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) Authentication = ХЭН бэ? (нэвтрэлт), Authorization = ЮУ хийж болох вэ? (эрх)
  • C) Authentication = эрх, Authorization = нэвтрэлт
  • D) Хоёулаа нэвтрэлт

Зөв хариулт: B

Тайлбар: Authentication = Паспорт шалгах (хэн бэ?). Authorization = VIP билет шалгах (юу хийж болох вэ?). Эхлээд AuthN → дараа AuthZ.

Тест 27

API Versioning-ийн хамгийн түгээмэл арга аль нь вэ?

  • A) Хувилбар ашиглахгүй
  • B) URI Path — /api/v1/students
  • C) Зөвхөн Header
  • D) Зөвхөн Cookie

Зөв хариулт: B

Тайлбар: URI Path versioning = Хамгийн энгийн, тодорхой, түгээмэл. /api/v1/.../api/v2/.... Хуучин клиент v1 ашиглаж, шинэ клиент v2 ашиглана.

Тест 28

Swagger / OpenAPI юу хийдэг вэ?

  • A) Код бичих
  • B) API-ийн ИНТЕРАКТИВ баримт бичиг үүсгэх — endpoint, параметр, хариуг харуулах, шууд тестлэх
  • C) Мэдээллийн сан үүсгэх
  • D) Deploy хийх

Зөв хариулт: B

Тайлбар: Swagger UI = API-ийн бүх endpoint, параметр, хариуг визуал харуулж, "Try it out" товчоор шууд тестлэх боломжтой.

Тест 29

Rate Limiting юу хийдэг вэ?

  • A) Код хурдасгах
  • B) Нэг клиентийн хэт олон хүсэлтийг ХЯЗГААРЛАХ — DDoS, abuse-аас хамгаалах
  • C) Мэдээллийн сан optimize хийх
  • D) Тест ажиллуулах

Зөв хариулт: B

Тайлбар: Rate Limiting = Жишээ: 1 минутад 100 хүсэлт. Хэтэрвэл 429 Too Many Requests. API-ийн тогтвортой байдал, аюулгүй байдлыг хамгаална.

Тест 30

HATEOAS гэж юу вэ?

  • A) HTTP протокол
  • B) Response дотор дараагийн боломжит үйлдлүүдийн ХОЛБООС (link) агуулах REST зарчим
  • C) Мэдээллийн сан
  • D) Тестийн framework

Зөв хариулт: B

Тайлбар: HATEOAS = Response дотор _links хэсэгт self, update, delete, courses зэрэг холбоос. Клиент API-г "судалж" (discover) ашиглаж чадна.

Тест 31

REST vs GraphQL — GraphQL-ийн давуу тал юу вэ?

  • A) Хурдан
  • B) Клиент яг ХЭРЭГТЭЙ талбаруудаа сонгож авна — over-fetching, under-fetching-гүй
  • C) Суралцахад хялбар
  • D) Бүх тохиолдолд REST-ээс дээр

Зөв хариулт: B

Тайлбар: GraphQL = Нэг endpoint, клиент query-ээр хэрэгтэй талбаруудаа л авна. REST = Олон endpoint, бүх талбар буцна (over-fetching). Гэхдээ GraphQL суралцахад хэцүү.

Тест 32

Content-Type: application/json header юу гэсэн утгатай вэ?

  • A) HTML файл
  • B) Хүсэлт/хариуны АГУУЛГА нь JSON формат
  • C) XML файл
  • D) Текст файл

Зөв хариулт: B

Тайлбар: Content-Type = Илгээж буй агуулгын формат. application/json = JSON. Сервер, клиент хоёулаа өгөгдлийг зөв боловсруулахад ашиглана.

Тест 33

Authorization: Bearer eyJhbGci... header юу хийдэг вэ?

  • A) JSON илгээх
  • B) JWT Token дамжуулж, нэвтрэлтийг баталгаажуулах
  • C) Content type тохируулах
  • D) Cache тохируулах

Зөв хариулт: B

Тайлбар: Bearer = Токен төрлийн нэвтрэлт. Сервер token-ийг шалгаж, хэн бэ, ямар эрхтэйг мэднэ. Хүсэлт бүрт header-ээр дамжуулна.

Тест 34

Spring Boot-д @Transactional annotation юу хийдэг вэ?

  • A) Тест ажиллуулах
  • B) Методын бүх DB үйлдлийг НЭГ transaction-д багтааж, алдаа гарвал БҮГДИЙГ буцаах (rollback)
  • C) Лог бичих
  • D) Cache тохируулах

Зөв хариулт: B

Тайлбар: @Transactional = Бүх DB үйлдэл амжилттай бол commit, нэг ч алдаа гарвал бүгдийг rollback. Өгөгдлийн бүрэн бүтэн байдал (ACID).

Тест 35

"Over-fetching" гэж юу вэ?

  • A) Хэрэгцээнээс бага мэдээлэл ирэх
  • B) Хэрэгцээнээс ИЛҮҮ мэдээлэл ирэх — зөвхөн нэр хэрэгтэй, бүх талбар ирэх
  • C) Алдаа гарах
  • D) Сервер унах

Зөв хариулт: B

Тайлбар: Over-fetching = REST-ийн нийтлэг асуудал. GET /students/1 → Зөвхөн нэр хэрэгтэй ч, бүх талбар (email, gpa, status...) ирнэ. GraphQL энэ асуудлыг шийднэ.

Тест 36

"Under-fetching" гэж юу вэ?

  • A) Хэрэгцээнээс илүү мэдээлэл ирэх
  • B) Нэг хүсэлтээр хүрэлцэхгүй — нэмэлт хүсэлт шаардагдах
  • C) Серверийн алдаа
  • D) Validation алдаа

Зөв хариулт: B

Тайлбар: Under-fetching = /students/1 авсан, гэхдээ хичээлүүдийг авахын тулд /students/1/courses дахин дуудах хэрэгтэй. GraphQL нэг query-ээр шийднэ.

Тест 37

Layered Architecture-д Controller → Service → Repository дарааллын зорилго юу вэ?

  • A) Зөвхөн дүрэм
  • B) Үүрэг хуваарилалт — Controller = HTTP, Service = Бизнес логик, Repository = DB
  • C) Зөвхөн хурд
  • D) Зөвхөн аюулгүй байдал

Зөв хариулт: B

Тайлбар: Давхарт архитектур = Separation of Concerns. Controller нь HTTP-ийг удирдана, Service нь бизнес дүрэм хариуцна, Repository нь DB-тай харилцана. Тус тусдаа тестлэж болно.

Тест 38

JpaRepository юу хийдэг вэ?

  • A) Controller үүсгэх
  • B) CRUD методуудыг АВТОМАТААР олгох — findAll, findById, save, deleteById г.м.
  • C) Тест бичих
  • D) JSON хөрвүүлэх

Зөв хариулт: B

Тайлбар: JpaRepository<Student, Long> extend хийхэд findAll(), findById(), save(), deleteById() зэрэг методууд автоматаар бэлэн болно. SQL бичих шаардлагагүй.

Тест 39

Java record юу хийдэг вэ?

  • A) Файл бичих
  • B) Immutable data class — constructor, getter, equals, hashCode, toString автоматаар үүсгэх
  • C) Exception шидэх
  • D) Лог бичих

Зөв хариулт: B

Тайлбар: record StudentResponse(Long id, String name) {} = Immutable DTO. Getter, constructor, equals, hashCode, toString автомат. DTO-д маш тохиромжтой.

Тест 40

@NotBlank ба @NotNull-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) @NotNull = null биш, @NotBlank = null биш + хоосон string биш + зөвхөн хоосон зай биш
  • C) @NotBlank нь тоонд ашиглагдана
  • D) @NotNull нь String-д ашиглагддаггүй

Зөв хариулт: B

Тайлбар: @NotNull = null биш байхад хангалттай (хоосон "" зөвшөөрнө). @NotBlank = null биш + "" биш + " " биш. String-д @NotBlank илүү тохиромжтой.

Тест 41

HTTP 204 No Content хэзээ буцаадаг вэ?

  • A) GET хүсэлтэд
  • B) DELETE амжилттай — хариу body хоосон
  • C) POST хүсэлтэд
  • D) Алдаа гарахад

Зөв хариулт: B

Тайлбар: 204 = Амжилттай, гэхдээ буцаах өгөгдөл байхгүй. DELETE амжилттай → 204 No Content. Body хоосон.

Тест 42

HTTP 409 Conflict хэзээ буцаадаг вэ?

  • A) Нөөц олдсонгүй
  • B) Давхардсан мэдээлэл (жишээ: имэйл бүртгэлтэй) — бизнес дүрмийн зөрчил
  • C) Серверийн алдаа
  • D) Нэвтрэлт шаардлагатай

Зөв хариулт: B

Тайлбар: 409 Conflict = Хүсэлт формат зөв, гэхдээ бизнес дүрэмтэй зөрчилдөж байна. Жишээ: "batbold@example.com имэйл бүртгэлтэй байна."

Тест 43

@RequestParam ба @PathVariable-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) @PathVariable = URL зам (/students/1), @RequestParam = Query (?page=1)
  • C) Хоёулаа body-аас авна
  • D) Хоёулаа header-аас авна

Зөв хариулт: B

Тайлбар: /students/{id}@PathVariable Long id. ?page=1&size=10@RequestParam int page. Нөөцийн ID = Path, шүүлт/хуудас = Query.

Тест 44

@PostMapping annotation юу хийдэг вэ?

  • A) GET хүсэлт хүлээн авах
  • B) HTTP POST хүсэлтийг тухайн метод руу чиглүүлэх
  • C) DELETE хүсэлт хүлээн авах
  • D) Бүх хүсэлт хүлээн авах

Зөв хариулт: B

Тайлбар: @PostMapping = HTTP POST хүсэлт → Шинэ нөөц үүсгэх. @GetMapping = GET, @PutMapping = PUT, @DeleteMapping = DELETE.

Тест 45

Spring Boot application.yml файл юунд ашигладаг вэ?

  • A) Код бичих
  • B) Програмын ТОХИРГОО — port, database URL, JPA тохиргоо зэрэг
  • C) Тест бичих
  • D) HTML бичих

Зөв хариулт: B

Тайлбар: application.yml = Програмын бүх тохиргоо. server.port, spring.datasource.url, spring.jpa.hibernate.ddl-auto зэрэг. Hardcode-гүй.

Тест 46

cURL гэж юу вэ?

  • A) Програмчлалын хэл
  • B) Командын мөрөөс HTTP хүсэлт илгээх хэрэгсэл
  • C) Мэдээллийн сан
  • D) IDE

Зөв хариулт: B

Тайлбар: cURL = Terminal-аас API тестлэх. curl -X POST http://localhost:8080/api/v1/students -H "Content-Type: application/json" -d '{"name":"Бат"}'.

Тест 47

H2 Database юу вэ?

  • A) Production мэдээллийн сан
  • B) Java-д суулгасан жижиг мэдээллийн сан — хөгжүүлэлт, тестэд тохиромжтой (in-memory)
  • C) NoSQL мэдээллийн сан
  • D) Кеш систем

Зөв хариулт: B

Тайлбар: H2 = In-memory DB. Програм ажиллаж байх үед л өгөгдөл хадгалагдана. Хөгжүүлэлт, тестэд маш тохиромжтой. Production-д PostgreSQL, MySQL ашиглана.

Тест 48

spring.jpa.hibernate.ddl-auto=create-drop юу хийдэг вэ?

  • A) Зөвхөн уншиx
  • B) Програм эхлэхэд хүснэгт ҮҮСГЭЖ, зогсоход УСТГАХ
  • C) Зөвхөн шинэчлэх
  • D) Юу ч хийхгүй

Зөв хариулт: B

Тайлбар: create-drop = Хөгжүүлэлтийн орчинд тохиромжтой. Production-д validate эсвэл none ашиглана. update = Хүснэгтийг шинэчлэх (устгахгүй).

Тест 49

RESTful API-д URI-д camelCase ашиглаж болох уу?

  • A) Зөвшөөрнө
  • B) Болохгүй — жижиг үсэг + зураас (-) ашиглах: /course-enrollments
  • C) PascalCase ашиглана
  • D) UPPER_CASE ашиглана

Зөв хариулт: B

Тайлбар: URI стандарт: Жижиг үсэг + зураас. /course-enrollments = Зөв. /courseEnrollments = camelCase буруу. URI нь case-sensitive → Стандарт чухал.

Тест 50

@Service annotation юу хийдэг вэ?

  • A) Controller зарлах
  • B) Spring Bean зарлах — бизнес логик агуулсан Service давхаргын класс
  • C) Entity зарлах
  • D) Тест зарлах

Зөв хариулт: B

Тайлбар: @Service = Spring IoC Container-д Bean болж бүртгэгдэнэ. Constructor Injection-аар бусад Bean-д тарина. Бизнес логик = Service давхарга.

Тест 51

Pagination-д page=0&size=10 гэсэн параметрүүд юу гэсэн утгатай вэ?

  • A) 0 бичлэг, 10 хуудас
  • B) Эхний хуудас (0-indexed), хуудас бүрт 10 бичлэг
  • C) 10-р хуудас
  • D) 0-аас 10 хүртэлх ID

Зөв хариулт: B

Тайлбар: page=0 = Эхний хуудас (0-indexed). size=10 = Хуудас бүрт 10 бичлэг. 150 бичлэг → 15 хуудас (0-14).

Тест 52

API-д Location header хэзээ буцаадаг вэ?

  • A) GET хүсэлтэд
  • B) POST → 201 Created — Шинэ нөөцийн URL-ийг Location header-т буцаах
  • C) DELETE хүсэлтэд
  • D) Бүх хүсэлтэд

Зөв хариулт: B

Тайлбар: POST /students → 201 Created + Location: /api/v1/students/5. Клиент шинэ нөөцийн хаягийг мэдэж, шууд хандаж болно.

Тест 53

gRPC нь REST-ээс юугаараа ялгаатай вэ?

  • A) Ялгаагүй
  • B) HTTP/2 + Protocol Buffers (binary) ашигладаг — илүү хурдан, бага хэмжээтэй
  • C) Зөвхөн JSON ашигладаг
  • D) Зөвхөн GET метод

Зөв хариулт: B

Тайлбар: gRPC = HTTP/2 + Protobuf (binary). JSON-оос 5-10x жижиг, хурдан. Microservice хоорондын харилцаанд тохиромжтой. Гэхдээ browser шууд ашиглахад хэцүү.

Тест 54

OAuth 2.0 юу хийдэг вэ?

  • A) Мэдээллийн сан
  • B) Гуравдагч этгээдээр (Google, Facebook) нэвтрэх стандарт протокол
  • C) API баримт бичиг
  • D) Тест framework

Зөв хариулт: B

Тайлбар: OAuth 2.0 = "Google-ээр нэвтрэх". Хэрэглэгч нууц үгээ манай системд ӨГӨХГҮЙГЭЭР, Google-ээр баталгаажуулж нэвтэрнэ. Access Token авна.

Тест 55

API Key ба JWT-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) API Key = Энгийн түлхүүр (хэн бэ мэдэхгүй), JWT = Хэрэглэгчийн мэдээлэл агуулсан токен
  • C) JWT нь аюулгүй биш
  • D) API Key нь илүү аюулгүй

Зөв хариулт: B

Тайлбар: API Key = Хаалганы түлхүүр (хэн барьж байгаа мэдэхгүй). JWT = Паспорт (хэн, ямар эрхтэй, хэзээ дуусах мэдээлэл агуулагдана).

Тест 56

Дараах кодын гол асуудал юу вэ?

@GetMapping("/students")
public List<Student> findAll() {
    return repository.findAll();
}
  • A) Асуудалгүй
  • B) Entity-г шууд буцааж байна — DTO ашиглах ёстой
  • C) Нэрлэлт буруу
  • D) Annotation буруу

Зөв хариулт: B

Тайлбар: Entity шууд буцаавал: password зэрэг нууц талбар задарна, Entity өөрчлөхөд API эвдэрнэ. StudentResponse DTO ашиглах ёстой.

Тест 57

@ExceptionHandler annotation юу хийдэг вэ?

  • A) Exception үүсгэх
  • B) Тодорхой Exception төрлийг барьж, тохирсон хариу буцаах метод зарлах
  • C) Бүх алдааг нуух
  • D) Лог бичих

Зөв хариулт: B

Тайлбар: @ExceptionHandler(StudentNotFoundException.class) = StudentNotFoundException гарахад энэ метод ажиллаж, 404 + ErrorResponse буцаана.

Тест 58

Дараах status code-ийн зөв хэрэглээ аль нь вэ?

  • A) POST амжилттай → 200
  • B) POST амжилттай → 201 Created
  • C) POST амжилттай → 204
  • D) POST амжилттай → 301

Зөв хариулт: B

Тайлбар: POST = Шинэ нөөц үүсгэх → 201 Created + Location header. 200 = Ерөнхий амжилт (GET-д). 204 = Агуулга хоосон (DELETE-д).

Тест 59

@Column(unique = true) юу хийдэг вэ?

  • A) Тогтмол хувьсагч
  • B) Мэдээллийн сангийн баганад ДАВТАГДАШГҮЙ хязгаарлалт тавих
  • C) Primary key болгох
  • D) Index үүсгэх

Зөв хариулт: B

Тайлбар: @Column(unique = true) = Email зэрэг давтагдаж болохгүй утга. Хоёр оюутан ижил имэйлтэй байж болохгүй → DB-д unique constraint.

Тест 60

Serialization ба Deserialization гэж юу вэ?

  • A) Ялгаагүй
  • B) Serialization = Java объект → JSON. Deserialization = JSON → Java объект
  • C) Хоёулаа JSON → объект
  • D) Хоёулаа объект → JSON

Зөв хариулт: B

Тайлбар: Response буцахад: Student → JSON (Serialization). Request ирэхэд: JSON → StudentCreateRequest (Deserialization). Jackson library автоматаар хийнэ.

Тест 61

REST API-д Idempotent key юунд хэрэгтэй вэ?

  • A) Формат солиход
  • B) Сүлжээний алдаанаас давхар POST (давхар үүсгэлт) гарахаас сэргийлэх
  • C) Зөвхөн хурд нэмэх
  • D) Лог бичих

Зөв хариулт: B

Тайлбар: Клиент POST илгээсэн, хариу ирэхгүй → Дахин илгээх → 2 дахь нөөц үүсэх! Idempotency-Key header ашиглавал сервер давхар хүсэлтийг мэдэж, ижил хариу буцаана.

Тест 62

Spring Boot-д @GeneratedValue(strategy = GenerationType.IDENTITY) юу хийдэг вэ?

  • A) Гараар ID оноох
  • B) DB автоматаар ID үүсгэх (auto-increment)
  • C) UUID үүсгэх
  • D) Timestamp үүсгэх

Зөв хариулт: B

Тайлбар: IDENTITY = Мэдээллийн сан auto-increment ашиглан ID үүсгэнэ. Оюутан нэмэх бүрт ID автоматаар 1, 2, 3... болж нэмэгднэ.

Тест 63

@Enumerated(EnumType.STRING) юу хийдэг вэ?

  • A) Тоогоор хадгалах
  • B) Enum утгыг DB-д STRING болгон хадгалах (жишээ: "ACTIVE", "INACTIVE")
  • C) JSON руу хөрвүүлэх
  • D) Validation хийх

Зөв хариулт: B

Тайлбар: EnumType.STRING = "ACTIVE" гэж хадгална. EnumType.ORDINAL = 0, 1, 2 гэж хадгална (Enum дараалал өөрчлөгдвөл эвдэрнэ → STRING ашиглах).

Тест 64

Page<T> объект юу агуулдаг вэ?

  • A) Зөвхөн өгөгдөл
  • B) Өгөгдөл + хуудсын мэдээлэл (нийт бичлэг, нийт хуудас, одоогийн хуудас)
  • C) Зөвхөн тоо
  • D) Зөвхөн хуудсын дугаар

Зөв хариулт: B

Тайлбар: Page<StudentResponse> = content (өгөгдлийн жагсаалт) + totalElements, totalPages, number (хуудсын дугаар), size. Клиент хуудаслалтыг хялбар хийнэ.

Тест 65

CORS (Cross-Origin Resource Sharing) гэж юу вэ?

  • A) Кеш систем
  • B) Өөр домэйноос API дуудахыг зөвшөөрөх/хориглох механизм
  • C) Мэдээллийн сан
  • D) Тестийн framework

Зөв хариулт: B

Тайлбар: CORS = localhost:3000 (React) → localhost:8080 (API). Өөр домэйн = Cross-Origin. Сервер @CrossOrigin эсвэл CORS тохиргоогоор зөвшөөрнө.

Тест 66

@CrossOrigin annotation юу хийдэг вэ?

  • A) Exception зохицуулах
  • B) Тодорхой домэйноос API руу хандахыг ЗӨВШӨӨРӨХ (CORS)
  • C) Validation хийх
  • D) Лог бичих

Зөв хариулт: B

Тайлбар: @CrossOrigin(origins = "http://localhost:3000") = React frontend-аас хандахыг зөвшөөрнө. Production-д тодорхой домэйнууд л зөвшөөрөх.

Тест 67

Дараах аль нь REST API best practice БИШ вэ?

  • A) Нөөц төвтэй URI
  • B) HTTP метод зөв ашиглах
  • C) Entity-г шууд API-аар буцаах
  • D) Validation хийх

Зөв хариулт: C

Тайлбар: Entity шууд буцаах = Best practice БИШ. DTO ашиглах = Best practice. Нууц мэдээлэл задрах, API-Entity хатуу холбогдох эрсдэлтэй.

Тест 68

HTTP 429 status code юу гэсэн утгатай вэ?

  • A) Серверийн алдаа
  • B) Хэт олон хүсэлт (Too Many Requests) — Rate Limit хэтэрсэн
  • C) Нөөц олдсонгүй
  • D) Нэвтрэлт шаардлагатай

Зөв хариулт: B

Тайлбар: 429 = Rate Limiting-д хүрсэн. "1 минутад 100 хүсэлт" хязгаар хэтэрсэн. Retry-After header-т хэзээ дахин оролдохыг заана.

Тест 69

@RequestMapping("/api/v1/students") юу хийдэг вэ?

  • A) Тест зарлах
  • B) Тухайн Controller-ийн БҮХИЙ Endpoint-ийн суурь URL тодорхойлох
  • C) Entity зарлах
  • D) Validation хийх

Зөв хариулт: B

Тайлбар: @RequestMapping("/api/v1/students") = Класс түвшинд. Дотор @GetMapping("/{id}") → Бүтэн URL: /api/v1/students/{id}.

Тест 70

Дараах аль нь "Safe" HTTP метод вэ?

  • A) POST
  • B) GET — Сервер дээрх өгөгдлийг ӨӨРЧЛӨХГҮЙ
  • C) DELETE
  • D) PUT

Зөв хариулт: B

Тайлбар: Safe = Сервер дээрх state-ийг өөрчлөхгүй. GET, HEAD, OPTIONS = Safe. POST, PUT, PATCH, DELETE = Unsafe (state өөрчилнө).

Тест 71

REST-ийн "Uniform Interface" зарчим юу вэ?

  • A) Нэг хэл ашиглах
  • B) URL, HTTP метод, JSON зэргийг НЭГДМЭЛ, СТАНДАРТ дүрмээр ашиглах
  • C) Нэг сервер ашиглах
  • D) Нэг клиент ашиглах

Зөв хариулт: B

Тайлбар: Uniform Interface = REST-ийн гол зарчим. Бүх нөөц ижил дүрмээр (URL = noun, HTTP method = verb, JSON = формат). Стандарт → Бүх хөгжүүлэгч ойлгоно.

Тест 72

"Cacheable" зарчим яагаад чухал вэ?

  • A) Аюулгүй байдал
  • B) Хариуг кэшлэж, давтан хүсэлтэд хурдан хариулах — серверийн ачааллыг бууруулах
  • C) Зөвхөн формат
  • D) Зөвхөн нэрлэлт

Зөв хариулт: B

Тайлбар: GET хариуг кэшлэж болно → Дахин дуудахад серверт хандахгүй, кэшээс авна. Cache-Control, ETag header-аар удирдана.

Тест 73

ETag header юунд ашигладаг вэ?

  • A) Нэвтрэлт
  • B) Нөөцийн хувилбарыг мэдэх — өөрчлөгдсөн эсэхийг шалгаж, шаардлагагүй дамжуулалтаас зайлсхийх
  • C) Rate limiting
  • D) CORS

Зөв хариулт: B

Тайлбар: ETag: "abc123" = Нөөцийн fingerprint. Клиент If-None-Match: "abc123" header-ээр дуудна → Өөрчлөгдөөгүй бол 304 Not Modified (body илгээхгүй).

Тест 74

API Gateway юу хийдэг вэ?

  • A) Код бичих
  • B) Бүх API хүсэлтийг нэг цэгээр дамжуулж, routing, auth, rate limiting, load balancing хийх
  • C) Тест ажиллуулах
  • D) Мэдээллийн сан удирдах

Зөв хариулт: B

Тайлбар: API Gateway = Бүх хүсэлтийн "нэг хаалга". Routing (аль сервис рүү чиглүүлэх), Authentication, Rate Limiting, Load Balancing. Жишээ: Kong, AWS API Gateway.

Тест 75

"Content Negotiation" гэж юу вэ?

  • A) Нэвтрэлт
  • B) Клиент хүссэн формат (JSON/XML)-аар хариу буцаах — Accept header ашиглах
  • C) Rate limiting
  • D) Validation

Зөв хариулт: B

Тайлбар: Клиент Accept: application/json → JSON хариу. Accept: application/xml → XML хариу. Сервер клиентийн хүсэлтийн дагуу формат сонгоно.

Тест 76

Дараах аль нь зөв Error Response формат вэ?

  • A) {"error": "fail"}
  • B) {"status": 404, "error": "Not Found", "message": "ID=5 оюутан олдсонгүй", "timestamp": "...", "path": "/api/v1/students/5"}
  • C) "Something went wrong"
  • D) 500

Зөв хариулт: B

Тайлбар: Сайн Error Response = status + error + тодорхой message + timestamp + path. Клиент алдааг ОЙЛГОЖ, дебаг хийж чадна.

Тест 77

@Tag annotation (Swagger) юу хийдэг вэ?

  • A) Тест бичих
  • B) Swagger UI дээр endpoint-уудыг БҮЛЭГЛЭЖ, нэр, тайлбар өгөх
  • C) Validation хийх
  • D) Exception зохицуулах

Зөв хариулт: B

Тайлбар: @Tag(name = "Student API", description = "Оюутны CRUD API") = Swagger UI дээр endpoint-уудыг "Student API" бүлэг дотор харуулна.

Тест 78

@Operation annotation (Swagger) юу хийдэг вэ?

  • A) Тест бичих
  • B) Тодорхой endpoint-ийн summary, description, response бичих — Swagger UI-д харуулах
  • C) Validation хийх
  • D) Exception зохицуулах

Зөв хариулт: B

Тайлбар: @Operation(summary = "Бүх оюутан авах") = Swagger UI-д endpoint бүрийн тайлбар харуулна. API баримт бичиг = Хөгжүүлэгчийн хамгийн сайн найз.

Тест 79

Webhook ба REST API-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) REST = Клиент ДУУДНА (pull), Webhook = Сервер МЭДЭГДЭНЭ (push) — үйл явдал гарахад
  • C) Webhook нь илүү хурдан
  • D) REST нь илүү аюулгүй

Зөв хариулт: B

Тайлбар: REST = Клиент хэзээ хүсвэл дуудна (polling). Webhook = Үйл явдал гарахад сервер клиентийн URL руу POST хүсэлт илгээнэ (real-time мэдэгдэл).

Тест 80

HTTPS нь HTTP-ээс юугаараа ялгаатай вэ?

  • A) Ялгаагүй
  • B) TLS/SSL шифрлэлт нэмсэн — мэдээлэл шифрлэгдэж дамжуулагдана
  • C) Хурдан
  • D) Зөвхөн GET ашигладаг

Зөв хариулт: B

Тайлбар: HTTPS = HTTP + TLS шифрлэлт. Мэдээлэл (password, token, хувийн мэдээлэл) шифрлэгдэж дамжуулагдана → Man-in-the-middle халдлагаас хамгаална.

Тест 81

Дараах аль нь Richardson Maturity Model-ийн хамгийн дээд түвшин вэ?

  • A) Level 0 — Нэг endpoint, нэг метод
  • B) Level 3 — HATEOAS (Hypermedia Controls)
  • C) Level 1 — Resources
  • D) Level 2 — HTTP Verbs

Зөв хариулт: B

Тайлбар: Level 0 = Нэг URI, POST. Level 1 = Нөөц төвтэй URI. Level 2 = HTTP метод зөв. Level 3 = HATEOAS. Дээд түвшин = "Жинхэнэ REST".

Тест 82

@Size(min=2, max=100) annotation юу хийдэг вэ?

  • A) Тоон хязгаар
  • B) String-ийн УРТТАЙ 2-100 тэмдэгт хязгаар тавих
  • C) Массивын хэмжээ
  • D) Бүх төрөлд ашиглана

Зөв хариулт: B

Тайлбар: @Size(min=2, max=100) = String утгын урт 2-100 тэмдэгт байх ёстой. Хэт богино нэр ("A"), хэт урт нэр зайлсхийнэ.

Тест 83

@Min ба @Max annotation юунд ашигладаг вэ?

  • A) String-д
  • B) Тоон утгын доод/дээд ХЯЗГААР тавих — @Min(0) @Max(4) Double gpa
  • C) Boolean-д
  • D) Огноонд

Зөв хариулт: B

Тайлбар: @Min(0) @Max(4) = GPA 0.0-4.0 хооронд байх ёстой. Хязгаараас гадуур утга ирвэл 400 Bad Request.

Тест 84

Microservice архитектурт API яагаад чухал вэ?

  • A) Шаардлагагүй
  • B) Microservice бүр тусдаа, API-аар л бие биетэйгээ ХАРИЛЦАНА
  • C) Зөвхөн нэг сервис байна
  • D) Мэдээллийн сан хуваалцана

Зөв хариулт: B

Тайлбар: Microservice = Жижиг, бие даасан сервисүүд. Student Service ↔ Course Service ↔ Payment Service. Бүгд API (REST/gRPC)-аар харилцана. API = Microservice-ийн "хэл".

Тест 85

"Contract-First" API дизайн гэж юу вэ?

  • A) Эхлээд код бичих
  • B) Эхлээд API-ийн ТОДОРХОЙЛОЛТ (OpenAPI spec) бичиж, дараа нь кодыг бичих
  • C) Зөвхөн тест бичих
  • D) Баримт бичиг бичэхгүй

Зөв хариулт: B

Тайлбар: Contract-First = OpenAPI YAML/JSON эхлээд бичих → Frontend, Backend баг зэрэг ажиллаж чадна. API-ийн "гэрээг" эхлээд тохирох.

Тест 86

ResponseEntity.noContent().build() юу буцаадаг вэ?

  • A) 200 OK + JSON
  • B) 204 No Content — Body хоосон
  • C) 404 Not Found
  • D) 500 Error

Зөв хариулт: B

Тайлбар: noContent() = 204 status code, body хоосон. DELETE амжилттай → Устгасан тул буцаах өгөгдөл байхгүй.

Тест 87

ResponseEntity.created(location).body(dto) юу буцаадаг вэ?

  • A) 200 OK
  • B) 201 Created + Location header + DTO body
  • C) 204 No Content
  • D) 404 Not Found

Зөв хариулт: B

Тайлбар: POST амжилттай → 201 + Location: /api/v1/students/5 (шинэ нөөцийн URL) + Body: StudentResponse JSON.

Тест 88

"Backward Compatibility" яагаад API-д чухал вэ?

  • A) Чухал биш
  • B) Хуучин клиентүүд API шинэчлэгдсэн ч ЭВДРЭХГҮЙ үргэлжлүүлэн ажиллах
  • C) Зөвхөн хурд
  • D) Зөвхөн аюулгүй байдал

Зөв хариулт: B

Тайлбар: v1 API → v2 нэмэхдээ v1-ийг УСТГАХГҮЙ. Мобайл апп (хуучин хувилбар) v1 ашиглаж байна → Устгавал апп эвдэрнэ. Шинэ → v2, хуучин → v1 хэвээр.

Тест 89

@Email annotation юу шалгадаг вэ?

  • A) Нэр
  • B) String утга имэйл ФОРМАТ-д нийцэж байгаа эсэхийг шалгах
  • C) Нас
  • D) ID

Зөв хариулт: B

Тайлбар: @Email = "batbold@example.com" → Зөв. "not-email" → Буруу → 400 Bad Request + "Имэйл формат буруу".

Тест 90

Spring Boot-д orElseThrow() юу хийдэг вэ?

  • A) Утга буцаах
  • B) Optional-д утга БАЙХГҮЙ бол Exception шидэх
  • C) Лог бичих
  • D) Null буцаах

Зөв хариулт: B

Тайлбар: repository.findById(id).orElseThrow(() -> new StudentNotFoundException(...)) = ID-аар олдохгүй бол Exception. Null буцаахгүй → NullPointerException-ээс хамгаалах.

Тест 91

Pageable interface юу хийдэг вэ?

  • A) HTML хуудас
  • B) Хуудаслалтын мэдээлэл (хуудсын дугаар, хэмжээ, эрэмбэ) Spring Data-д дамжуулах
  • C) Exception зохицуулах
  • D) JSON хөрвүүлэх

Зөв хариулт: B

Тайлбар: PageRequest.of(page, size, sort) = Pageable объект. Repository findAll(pageable) → DB-д LIMIT, OFFSET автоматаар нэмэгдэнэ.

Тест 92

"Idempotent" DELETE-ийн зөв ажиллагаа аль нь вэ?

  • A) 2 дахь DELETE-д 500 буцаах
  • B) 1 дахь DELETE → 204, 2 дахь DELETE → 404 (аль аль тохиолдолд нөөц байхгүй → идемпотент)
  • C) 2 дахь DELETE-д дахин устгах
  • D) Exception шидэх

Зөв хариулт: B

Тайлбар: Идемпотент = Үр дүн ижил. 1 удаа устгасан → 204. Дахин дуудвал → 404 (аль хэдийн устгагдсан). Хоёр тохиолдолд нөөц "устгагдсан" → Ижил.

Тест 93

API-д "Deprecation" гэж юу вэ?

  • A) Шинэ функц нэмэх
  • B) Хуучин endpoint/функцыг "хуучирсан" гэж тэмдэглэж, ирээдүйд устгахыг анхааруулах
  • C) Алдаа засах
  • D) Тест бичих

Зөв хариулт: B

Тайлбар: @Deprecated + Sunset header = "Энэ endpoint v2-д солигдсон. 2025-06-01-д устгагдана." Клиентэд шилжих хугацаа өгнө.

Тест 94

"N+1 Problem" гэж юу вэ?

  • A) Нэрлэлтийн асуудал
  • B) 1 query-ээр жагсаалт авч, бичлэг бүрд нэмэлт query ажиллуулах → N+1 query
  • C) Зөвхөн UI асуудал
  • D) Зөвхөн тестийн асуудал

Зөв хариулт: B

Тайлбар: 100 оюутан авах (1 query) + оюутан бүрийн хичээл авах (100 query) = 101 query! JPA @EntityGraph, JOIN FETCH, DTO projection-оор шийднэ.

Тест 95

Postman юу хийдэг вэ?

  • A) Код бичих
  • B) API тестлэх GUI хэрэгсэл — хүсэлт илгээх, хариу шалгах, collection хадгалах
  • C) Мэдээллийн сан
  • D) Deploy хийх

Зөв хариулт: B

Тайлбар: Postman = API тестлэх хамгийн түгээмэл GUI хэрэгсэл. Request илгээх, response шалгах, environment тохируулах, collection хуваалцах.

Тест 96

"API-First Design" гэж юу вэ?

  • A) Backend эхлээд бичих
  • B) API-ийн тодорхойлолтыг хамгийн ЭХЭНД бичиж, бүх баг тэр гэрээний дагуу ажиллах
  • C) Frontend эхлээд бичих
  • D) Тест эхлээд бичих

Зөв хариулт: B

Тайлбар: API-First = OpenAPI spec → Frontend + Backend зэрэг эхэлнэ. Mobile + Web + Partner бүгд ижил API гэрээ. Зөрчилдөл бага, хурд нэмнэ.

Тест 97

@Table(name = "students") annotation юу хийдэг вэ?

  • A) Controller тодорхойлох
  • B) Entity-г мэдээллийн сангийн "students" ХҮСНЭГТТЭЙ холбох
  • C) DTO тодорхойлох
  • D) Тест тодорхойлох

Зөв хариулт: B

Тайлбар: @Table(name = "students") = Java Student класс → DB-ийн "students" хүснэгт. Нэр зөрөх бол заавал зааж өгнө.

Тест 98

REST API-д "Bulk Operation" (олон бичлэг нэг дор) хэрхэн хийх вэ?

  • A) Нэг нэгээр дуудах
  • B) POST /students/batch — Request body-д олон бичлэг агуулсан массив дамжуулах
  • C) GET ашиглах
  • D) Боломжгүй

Зөв хариулт: B

Тайлбар: 100 оюутан нэмэх = 100 POST дуудах (удаан). POST /students/batch + [{...}, {...}] = Нэг хүсэлт. Network overhead бага, хурдан.

Тест 99

"Health Check" endpoint юу вэ?

  • A) Оюутны мэдээлэл
  • B) GET /actuator/health — Системийн ажиллагаа, DB холболт, дискний зай зэргийг шалгах
  • C) Тест ажиллуулах
  • D) Код шалгах

Зөв хариулт: B

Тайлбар: Health Check = Monitoring системүүд (Kubernetes, Load Balancer) API амьд байгаа эсэхийг шалгана. {"status": "UP"} → Ажиллаж байна.

Тест 100

REST API яагаад орчин үеийн програм хангамжийн бүтээлтэд хамгийн чухал вэ?

  • A) Зөвхөн нэг хэрэглээнд
  • B) Frontend-Backend, Mobile-Server, Microservice хоорондын ХЭЛНИЙ ҮЛ ХАМААРАН харилцах стандарт
  • C) Зөвхөн вэб хуудаст
  • D) Зөвхөн том компаниудад

Зөв хариулт: B

Тайлбар: REST API = Орчин үеийн системүүдийн "lingua franca" (нийтлэг хэл). React ↔ Spring Boot ↔ Mobile ↔ Гуравдагч систем. HTTP + JSON = Хэлний, платформын ялгаагүй. API сайн = Систем сайн.


📚 Ашигласан эх сурвалжууд:

  • Roy Fielding — Architectural Styles and the Design of Network-based Software Architectures (2000, PhD Dissertation)
  • Richardson, Leonard — RESTful Web APIs (O'Reilly, 2013)
  • Spring Boot Reference Documentation — docs.spring.io
  • OpenAPI Specification 3.0 — swagger.io/specification
  • RFC 7231 — HTTP/1.1 Semantics and Content
  • RFC 7519 — JSON Web Token (JWT)
  • Google API Design Guide — cloud.google.com/apis/design
  • Microsoft REST API Guidelines — github.com/microsoft/api-guidelines