Metadata-Version: 2.4
Name: anet-common
Version: 0.1.7
Summary: Common utilities, settings, and contracts for Anet Microservices (Django/DRF)
Home-page: https://github.com/murodalidev/anet-common/
Author: Murodali Narzullaev
Author-email: murodalinarzullaevofficial@gmail.uz
License: MIT
Keywords: django,drf,microservices,utilities,common
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 5.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: Django>=5.2
Requires-Dist: djangorestframework==3.16.1
Requires-Dist: drf-spectacular[sidecar]==0.29.0
Requires-Dist: django-modeltranslation==0.19.19
Requires-Dist: djangorestframework-camel-case>=1.4.2
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# Anet Common Library

Ushbu kutubxona Anet loyihasining mikroservislari uchun umumiy standartlar, sozlamalar va yordamchi vositalarni (utilities) o'z ichiga oladi.

## O'rnatish

```bash
pip install anet-common
```
*(Yoki private repodan o'rnatish)*

> **Eslatma:** `drf-spectacular[sidecar]` allaqachon dependency sifatida kiritilgan.
> Swagger UI va ReDoc statik fayllari CDN o'rniga lokal paketdan yuklanadi —
> tashqi internet mavjud bo'lmagan dev tarmoqlarda ham ishlaydi.

---

## Foydalanish

Mikroservisning `settings.py` faylida ushbu kutubxonadan standart konfiguratsiyalarni import qiling va ularni kengaytiring (extend).

### `settings.py` namunasi:

```python
from anet_common.conf import (
    COMMON_LANGUAGES,
    COMMON_MODELTRANSLATION_LANGUAGES,
    COMMON_REST_FRAMEWORK,
    COMMON_SPECTACULAR_SETTINGS,
    COMMON_SPECTACULAR_APPS,
)

# INSTALLED APPS
INSTALLED_APPS = [
    "modeltranslation",
    # ...
    "rest_framework",
    # ...
] + COMMON_SPECTACULAR_APPS
# COMMON_SPECTACULAR_APPS = ["drf_spectacular", "drf_spectacular_sidecar"]

# 1. MIDDLEWARE
MIDDLEWARE = [
    "anet_common.middleware.RequestIdMiddleware",  # Eng yuqorida tursin
    "django.middleware.locale.LocaleMiddleware",
    # ... boshqa middlewarelar
]

# 2. TILLAR VA VAQT
TIME_ZONE = "Asia/Tashkent"
LANGUAGE_CODE = "uz"
LANGUAGES = COMMON_LANGUAGES
# Natija: (('uz', "O'zbek"), ('ru', "Русский"), ('en', "English"))

MODELTRANSLATION_LANGUAGES = COMMON_MODELTRANSLATION_LANGUAGES
MODELTRANSLATION_DEFAULT_LANGUAGE = "uz"

# 3. DRF SOZLAMALARI
REST_FRAMEWORK = COMMON_REST_FRAMEWORK.copy()
REST_FRAMEWORK.update({
    # Loyihaga xos qo'shimchalar
    "DEFAULT_PERMISSION_CLASSES": (
        "rest_framework.permissions.IsAuthenticated",
    ),
})

# 4. SPECTACULAR (SWAGGER) SOZLAMALARI
# SWAGGER_UI_DIST va REDOC_DIST = "SIDECAR" allaqachon o'rnatilgan:
# statik fayllar CDN o'rniga drf_spectacular_sidecar paketidan yuklanadi.
SPECTACULAR_SETTINGS = COMMON_SPECTACULAR_SETTINGS.copy()
SPECTACULAR_SETTINGS.update({
    "TITLE": "Mening Mikroservis API",
    "DESCRIPTION": "Bu servis faqat ... uchun javob beradi",
    "VERSION": "1.0.0",
})

# 5. SERVIS MA'LUMOTLARI (Meta uchun)
SERVICE_NAME = "my-service"
SERVICE_VERSION = "v1"
```

### `urls.py` namunasi:

```python
from django.urls import path, include
from anet_common.spectacular.urls import urlpatterns as spectacular_urls

urlpatterns = [
    # Spectacular (Swagger UI + ReDoc) — lokal sidecar statikasidan
    path("api/", include(spectacular_urls)),
    # Natija:
    #   GET /api/schema/            — OpenAPI JSON/YAML schema
    #   GET /api/schema/swagger-ui/ — Swagger UI
    #   GET /api/schema/redoc/      — ReDoc

    # ... boshqa url'lar
]
```

> Swagger UI va ReDoc uchun URL prefix (`"api/"`) loyihaga qarab o'zgartirish mumkin.

### Statik fayllarni yig'ish

`drf_spectacular_sidecar` statik fayllarni paket ichida saqlaydi.
Deployment oldidan odatdagi `collectstatic` buyrug'i yetarli:

```bash
python manage.py collectstatic --noinput
```

### `views.py` da pagination namunasi:

```python
class TestAPIView(generics.APIView):  # or GenericAPIView
    queryset = MyObject.objects.all()
    serializer_class = MyObjectSerializer

    def get(self, request):
        qs = self.get_queryset()

        # 1. Querysetni sahifalash
        page = self.paginate_queryset(qs)

        # 2. Agar sahifalash muvaffaqiyatli bo'lsa
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(qs, many=True)
        return Response(serializer.data)
```

---

## Tarkibi va Konstantalar

### 1. `COMMON_LANGUAGES`
Loyiha qo'llab-quvvatlaydigan 3 ta asosiy til:
- `uz`: O'zbek
- `ru`: Rus
- `en`: Ingliz

### Umumiy `COMMON_` qiymatlarining tarkibi

```python
from django.utils.translation import gettext_lazy as _

# 1. COMMON LANGUAGES
COMMON_LANGUAGES = (
    ("uz", "O'zbek"),
    ("ru", "Русский"),
    ("en", "English"),
)

COMMON_MODELTRANSLATION_LANGUAGES = ("uz", "ru", "en")
COMMON_MODELTRANSLATION_DEFAULT_LANGUAGE = "uz"

# 2. COMMON REST FRAMEWORK SETTINGS
COMMON_REST_FRAMEWORK = {
    "DEFAULT_RENDERER_CLASSES": (
        "anet_common.drf.renderers.AnetJSONRenderer",
    ),
    "DEFAULT_PARSER_CLASSES": (
        "djangorestframework_camel_case.parser.CamelCaseJSONParser",
        "rest_framework.parsers.JSONParser",
        "rest_framework.parsers.FormParser",
        "rest_framework.parsers.MultiPartParser",
    ),
    "EXCEPTION_HANDLER": "anet_common.drf.exceptions.custom_exception_handler",
    "DEFAULT_PAGINATION_CLASS": "anet_common.drf.pagination.StandardPageNumberPagination",
    "PAGE_SIZE": 20,
    "DEFAULT_SCHEMA_CLASS": "anet_common.spectacular.schema.StandardAutoSchema",
    "TEST_REQUEST_DEFAULT_FORMAT": "json",
}

# 3. COMMON SPECTACULAR SETTINGS
# SWAGGER_UI_DIST, SWAGGER_UI_FAVICON_HREF, REDOC_DIST = "SIDECAR"
# => statik fayllar CDN o'rniga drf_spectacular_sidecar dan yuklanadi
COMMON_SPECTACULAR_SETTINGS = {
    "SERVE_INCLUDE_SCHEMA": False,
    "COMPONENT_SPLIT_REQUEST": True,
    "COMPONENT_NO_READ_ONLY_REQUIRED": True,
    "POSTPROCESSING_HOOKS": [
        "drf_spectacular.hooks.postprocess_schema_enums",
    ],
    "SWAGGER_UI_DIST": "SIDECAR",
    "SWAGGER_UI_FAVICON_HREF": "SIDECAR",
    "REDOC_DIST": "SIDECAR",
}

# 4. SPECTACULAR UCHUN ZARUR INSTALLED_APPS
COMMON_SPECTACULAR_APPS = [
    "drf_spectacular",
    "drf_spectacular_sidecar",
]
```

### 2. `COMMON_REST_FRAMEWORK`
Quyidagi standart sozlamalarni o'z ichiga oladi:
- **Renderer:** `AnetJSONRenderer` — javoblarni standart formatga o'tkazadi.
- **Parser:** `CamelCaseJSONParser` va standart parserlar.
- **Exception Handler:** `custom_exception_handler` — xatolarni katalogdan olib, yagona formatga o'tkazadi.
- **Pagination:** `StandardPageNumberPagination` (default `page_size=20`).

### 4. `meta.timing` — So'rov vaqti

Har bir javobda `meta.timing` maydoni avtomatik to'ldiriladi.
Buning uchun `RequestIdMiddleware` MIDDLEWARE ro'yxatida **eng yuqorida** turishi shart.

| Maydon | Ta'rif |
|---|---|
| `total_ms` | So'rov kelgandan JSON render tugagunga qadar to'liq vaqt |
| `breakdown.app_ms` | Middleware + view logikasi + ORM + serializer vaqti |
| `breakdown.renderer_ms` | Faqat JSON render qilish vaqti |

> **Eslatma:** `timing` maydoni faqat `RequestIdMiddleware` o'rnatilgan bo'lsa to'ldiriladi.
> Middleware mavjud bo'lmasa, `timing` meta ichida ko'rinmaydi.

### 3. Response Formati

#### A. Success — List (Pagination bilan)

```json
{
  "success": true,
  "status_code": 200,
  "data": [
    {"id": 1, "name": "Acme LLC"},
    {"id": 2, "name": "Beta LLC"}
  ],
  "errors": [],
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2026-01-21T10:15:30.123456+05:00",
    "service": "company-service",
    "version": "v1",
    "language": "uz",
    "pagination": {
      "page": 1,
      "page_size": 20,
      "total_items": 120,
      "total_pages": 6,
      "has_next": true,
      "has_prev": false
    },
    "timing": {
      "total_ms": 47.83,
      "breakdown": {
        "app_ms": 46.30,
        "renderer_ms": 1.53
      }
    }
  }
}
```

#### B. Success — Detail (Single Object)

```json
{
  "success": true,
  "status_code": 200,
  "data": {
    "id": 1,
    "name": "Acme LLC"
  },
  "errors": [],
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2026-01-21T10:15:30.123456+05:00",
    "service": "company-service",
    "version": "v1",
    "language": "uz",
    "timing": {
      "total_ms": 12.41,
      "breakdown": {
        "app_ms": 10.88,
        "renderer_ms": 1.53
      }
    }
  }
}
```

#### C. Error Response

Xatoliklar har doim `errors` ro'yxati ichida qaytadi. `data` null bo'ladi.
`details`: `raise MyException(extra_details={...})` deb chaqirilsa to'ldiriladi.

```json
{
  "success": false,
  "status_code": 404,
  "data": null,
  "errors": [
    {
      "code": "VAL-0001",
      "message": "Topilmadi",
      "detail_message": "No BookingItem matches the given query.",
      "field": "email",
      "source": null,
      "details": null
    }
  ],
  "meta": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timestamp": "2026-01-21T10:15:30.123456+05:00",
    "service": "auth-service",
    "version": "v1",
    "language": "uz",
    "timing": {
      "total_ms": 8.17,
      "breakdown": {
        "app_ms": 6.94,
        "renderer_ms": 1.23
      }
    }
  }
}
```

---

## Xatoliklar Katalogi

Xatoliklar markazlashgan JSON katalogi orqali boshqariladi.
Yangi xatolik qo'shish uchun kutubxona yangilanishi kerak.
