Update WIP.md with endpoint analysis
This commit is contained in:
parent
70fbc7a035
commit
104aedbcf4
487
docs/api-reference.md
Normal file
487
docs/api-reference.md
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
# API Reference
|
||||||
|
|
||||||
|
Auto-generated API documentation.
|
||||||
|
|
||||||
|
Last updated: kwork-api
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkClient
|
||||||
|
|
||||||
|
Kwork.ru API client.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
# Login with credentials
|
||||||
|
client = await KworkClient.login("username", "password")
|
||||||
|
|
||||||
|
# Or restore from token
|
||||||
|
client = KworkClient(token="your_web_auth_token")
|
||||||
|
|
||||||
|
# Make requests
|
||||||
|
catalog = await client.catalog.get_list(page=1)
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
#### `catalog()`
|
||||||
|
|
||||||
|
Catalog API.
|
||||||
|
|
||||||
|
#### `projects()`
|
||||||
|
|
||||||
|
Projects API.
|
||||||
|
|
||||||
|
#### `user()`
|
||||||
|
|
||||||
|
User API.
|
||||||
|
|
||||||
|
#### `reference()`
|
||||||
|
|
||||||
|
Reference data API.
|
||||||
|
|
||||||
|
#### `notifications()`
|
||||||
|
|
||||||
|
Notifications API.
|
||||||
|
|
||||||
|
#### `other()`
|
||||||
|
|
||||||
|
Other endpoints.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CatalogAPI
|
||||||
|
|
||||||
|
Catalog/Kworks API endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ProjectsAPI
|
||||||
|
|
||||||
|
Projects (freelance orders) API endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## UserAPI
|
||||||
|
|
||||||
|
User API endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ReferenceAPI
|
||||||
|
|
||||||
|
Reference data (cities, countries, etc.) endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NotificationsAPI
|
||||||
|
|
||||||
|
Notifications and messages endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## OtherAPI
|
||||||
|
|
||||||
|
Other API endpoints.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Models
|
||||||
|
|
||||||
|
Pydantic models used in API responses.
|
||||||
|
|
||||||
|
## KworkUser
|
||||||
|
|
||||||
|
User information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `username` | - | - |
|
||||||
|
| `avatar_url` | - | - |
|
||||||
|
| `is_online` | - | - |
|
||||||
|
| `rating` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkCategory
|
||||||
|
|
||||||
|
Category information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `slug` | - | - |
|
||||||
|
| `parent_id` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kwork
|
||||||
|
|
||||||
|
Kwork (service) information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `title` | - | - |
|
||||||
|
| `description` | - | - |
|
||||||
|
| `price` | - | - |
|
||||||
|
| `currency` | - | - |
|
||||||
|
| `category_id` | - | - |
|
||||||
|
| `seller` | - | - |
|
||||||
|
| `images` | - | - |
|
||||||
|
| `rating` | - | - |
|
||||||
|
| `reviews_count` | - | - |
|
||||||
|
| `created_at` | - | - |
|
||||||
|
| `updated_at` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkDetails
|
||||||
|
|
||||||
|
Extended kwork details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `full_description` | - | - |
|
||||||
|
| `requirements` | - | - |
|
||||||
|
| `delivery_time` | - | - |
|
||||||
|
| `revisions` | - | - |
|
||||||
|
| `features` | - | - |
|
||||||
|
| `faq` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PaginationInfo
|
||||||
|
|
||||||
|
Pagination metadata.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `current_page` | - | - |
|
||||||
|
| `total_pages` | - | - |
|
||||||
|
| `total_items` | - | - |
|
||||||
|
| `items_per_page` | - | - |
|
||||||
|
| `has_next` | - | - |
|
||||||
|
| `has_prev` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CatalogResponse
|
||||||
|
|
||||||
|
Catalog response with kworks and pagination.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `kworks` | - | - |
|
||||||
|
| `pagination` | - | - |
|
||||||
|
| `filters` | - | - |
|
||||||
|
| `sort_options` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project
|
||||||
|
|
||||||
|
Project (freelance order) information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `title` | - | - |
|
||||||
|
| `description` | - | - |
|
||||||
|
| `budget` | - | - |
|
||||||
|
| `budget_type` | - | - |
|
||||||
|
| `category_id` | - | - |
|
||||||
|
| `customer` | - | - |
|
||||||
|
| `status` | - | - |
|
||||||
|
| `created_at` | - | - |
|
||||||
|
| `updated_at` | - | - |
|
||||||
|
| `bids_count` | - | - |
|
||||||
|
| `skills` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ProjectsResponse
|
||||||
|
|
||||||
|
Projects list response.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `projects` | - | - |
|
||||||
|
| `pagination` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Review
|
||||||
|
|
||||||
|
Review information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `rating` | - | - |
|
||||||
|
| `comment` | - | - |
|
||||||
|
| `author` | - | - |
|
||||||
|
| `kwork_id` | - | - |
|
||||||
|
| `created_at` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ReviewsResponse
|
||||||
|
|
||||||
|
Reviews list response.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `reviews` | - | - |
|
||||||
|
| `pagination` | - | - |
|
||||||
|
| `average_rating` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notification
|
||||||
|
|
||||||
|
Notification information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `type` | - | - |
|
||||||
|
| `title` | - | - |
|
||||||
|
| `message` | - | - |
|
||||||
|
| `is_read` | - | - |
|
||||||
|
| `created_at` | - | - |
|
||||||
|
| `link` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NotificationsResponse
|
||||||
|
|
||||||
|
Notifications list response.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `notifications` | - | - |
|
||||||
|
| `unread_count` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dialog
|
||||||
|
|
||||||
|
Dialog (chat) information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `participant` | - | - |
|
||||||
|
| `last_message` | - | - |
|
||||||
|
| `unread_count` | - | - |
|
||||||
|
| `updated_at` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AuthResponse
|
||||||
|
|
||||||
|
Authentication response.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `success` | - | - |
|
||||||
|
| `user_id` | - | - |
|
||||||
|
| `username` | - | - |
|
||||||
|
| `web_auth_token` | - | - |
|
||||||
|
| `message` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ErrorDetail
|
||||||
|
|
||||||
|
Error detail from API.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `code` | - | - |
|
||||||
|
| `message` | - | - |
|
||||||
|
| `field` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## APIErrorResponse
|
||||||
|
|
||||||
|
Standard API error response.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `success` | - | - |
|
||||||
|
| `errors` | - | - |
|
||||||
|
| `message` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## City
|
||||||
|
|
||||||
|
City information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `country_id` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Country
|
||||||
|
|
||||||
|
Country information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `code` | - | - |
|
||||||
|
| `cities` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TimeZone
|
||||||
|
|
||||||
|
Timezone information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `offset` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Feature
|
||||||
|
|
||||||
|
Feature/addon information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `description` | - | - |
|
||||||
|
| `price` | - | - |
|
||||||
|
| `type` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Badge
|
||||||
|
|
||||||
|
User badge information.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `id` | - | - |
|
||||||
|
| `name` | - | - |
|
||||||
|
| `description` | - | - |
|
||||||
|
| `icon_url` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DataResponse
|
||||||
|
|
||||||
|
Generic data response wrapper.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `success` | - | - |
|
||||||
|
| `data` | - | - |
|
||||||
|
| `message` | - | - |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Errors
|
||||||
|
|
||||||
|
Exception classes for error handling.
|
||||||
|
|
||||||
|
## KworkError
|
||||||
|
|
||||||
|
Base exception for all Kwork API errors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkAuthError
|
||||||
|
|
||||||
|
Authentication/authorization error.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkApiError
|
||||||
|
|
||||||
|
API request error (4xx, 5xx).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkNotFoundError
|
||||||
|
|
||||||
|
Resource not found (404).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkRateLimitError
|
||||||
|
|
||||||
|
Rate limit exceeded (429).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkValidationError
|
||||||
|
|
||||||
|
Validation error (400).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## KworkNetworkError
|
||||||
|
|
||||||
|
Network/connection error.
|
||||||
|
|
||||||
|
---
|
||||||
212
docs/examples.md
Normal file
212
docs/examples.md
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
# Usage Examples
|
||||||
|
|
||||||
|
## Catalog
|
||||||
|
|
||||||
|
### Get Catalog List
|
||||||
|
|
||||||
|
```python
|
||||||
|
from kwork_api import KworkClient
|
||||||
|
|
||||||
|
async with KworkClient(token="token") as client:
|
||||||
|
catalog = await client.catalog.get_list(page=1, category_id=5)
|
||||||
|
|
||||||
|
for kwork in catalog.kworks:
|
||||||
|
print(f"{kwork.title}: {kwork.price} RUB")
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
if catalog.pagination:
|
||||||
|
print(f"Page {catalog.pagination.current_page} of {catalog.pagination.total_pages}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Kwork Details
|
||||||
|
|
||||||
|
```python
|
||||||
|
details = await client.catalog.get_details(kwork_id=123)
|
||||||
|
|
||||||
|
print(f"Title: {details.title}")
|
||||||
|
print(f"Price: {details.price}")
|
||||||
|
print(f"Description: {details.full_description}")
|
||||||
|
print(f"Delivery: {details.delivery_time} days")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Projects
|
||||||
|
|
||||||
|
### Get Projects List
|
||||||
|
|
||||||
|
```python
|
||||||
|
projects = await client.projects.get_list(page=1)
|
||||||
|
|
||||||
|
for project in projects.projects:
|
||||||
|
print(f"{project.title} - {project.budget} RUB")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Customer Orders
|
||||||
|
|
||||||
|
```python
|
||||||
|
orders = await client.projects.get_payer_orders()
|
||||||
|
|
||||||
|
for order in orders:
|
||||||
|
print(f"Order #{order.id}: {order.status}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Performer Orders
|
||||||
|
|
||||||
|
```python
|
||||||
|
orders = await client.projects.get_worker_orders()
|
||||||
|
|
||||||
|
for order in orders:
|
||||||
|
print(f"Work #{order.id}: {order.status}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## User
|
||||||
|
|
||||||
|
### Get User Info
|
||||||
|
|
||||||
|
```python
|
||||||
|
user_info = await client.user.get_info()
|
||||||
|
print(f"Username: {user_info.get('username')}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Reviews
|
||||||
|
|
||||||
|
```python
|
||||||
|
reviews = await client.user.get_reviews(page=1)
|
||||||
|
|
||||||
|
for review in reviews.reviews:
|
||||||
|
print(f"Rating: {review.rating}/5 - {review.comment}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Favorite Kworks
|
||||||
|
|
||||||
|
```python
|
||||||
|
favorites = await client.user.get_favorite_kworks()
|
||||||
|
|
||||||
|
for kwork in favorites:
|
||||||
|
print(f"Favorite: {kwork.title}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference Data
|
||||||
|
|
||||||
|
### Get Cities
|
||||||
|
|
||||||
|
```python
|
||||||
|
cities = await client.reference.get_cities()
|
||||||
|
|
||||||
|
for city in cities:
|
||||||
|
print(f"{city.id}: {city.name}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Countries
|
||||||
|
|
||||||
|
```python
|
||||||
|
countries = await client.reference.get_countries()
|
||||||
|
|
||||||
|
for country in countries:
|
||||||
|
print(f"{country.id}: {country.name}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Timezones
|
||||||
|
|
||||||
|
```python
|
||||||
|
timezones = await client.reference.get_timezones()
|
||||||
|
|
||||||
|
for tz in timezones:
|
||||||
|
print(f"{tz.id}: {tz.name} ({tz.offset})")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
### Get Notifications
|
||||||
|
|
||||||
|
```python
|
||||||
|
notifications = await client.notifications.get_list()
|
||||||
|
|
||||||
|
for notif in notifications.notifications:
|
||||||
|
print(f"{notif.title}: {notif.message}")
|
||||||
|
|
||||||
|
print(f"Unread: {notifications.unread_count}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fetch New Notifications
|
||||||
|
|
||||||
|
```python
|
||||||
|
new_notifications = await client.notifications.fetch()
|
||||||
|
print(f"New: {len(new_notifications.notifications)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get Dialogs
|
||||||
|
|
||||||
|
```python
|
||||||
|
dialogs = await client.notifications.get_dialogs()
|
||||||
|
|
||||||
|
for dialog in dialogs:
|
||||||
|
print(f"Dialog with {dialog.participant.username}: {dialog.last_message}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```python
|
||||||
|
from kwork_api import KworkAuthError, KworkApiError, KworkNotFoundError
|
||||||
|
|
||||||
|
try:
|
||||||
|
catalog = await client.catalog.get_list()
|
||||||
|
except KworkAuthError as e:
|
||||||
|
print(f"Authentication failed: {e}")
|
||||||
|
except KworkNotFoundError as e:
|
||||||
|
print(f"Resource not found: {e}")
|
||||||
|
except KworkApiError as e:
|
||||||
|
print(f"API error [{e.status_code}]: {e.message}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unexpected error: {e}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
async def fetch_all_pages():
|
||||||
|
all_kworks = []
|
||||||
|
|
||||||
|
for page in range(1, 10):
|
||||||
|
try:
|
||||||
|
catalog = await client.catalog.get_list(page=page)
|
||||||
|
all_kworks.extend(catalog.kworks)
|
||||||
|
|
||||||
|
if not catalog.pagination or not catalog.pagination.has_next:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Delay to avoid rate limiting
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
except KworkRateLimitError:
|
||||||
|
print("Rate limited, waiting...")
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
|
return all_kworks
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pagination Helper
|
||||||
|
|
||||||
|
```python
|
||||||
|
async def fetch_all_catalog():
|
||||||
|
"""Fetch all kworks from catalog with pagination."""
|
||||||
|
all_kworks = []
|
||||||
|
page = 1
|
||||||
|
|
||||||
|
while True:
|
||||||
|
catalog = await client.catalog.get_list(page=page)
|
||||||
|
all_kworks.extend(catalog.kworks)
|
||||||
|
|
||||||
|
if not catalog.pagination or not catalog.pagination.has_next:
|
||||||
|
break
|
||||||
|
|
||||||
|
page += 1
|
||||||
|
await asyncio.sleep(0.5) # Rate limiting
|
||||||
|
|
||||||
|
return all_kworks
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*More examples in the API Reference.*
|
||||||
81
docs/index.md
Normal file
81
docs/index.md
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Kwork API Documentation
|
||||||
|
|
||||||
|
Unofficial Python client for Kwork.ru API.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install kwork-api
|
||||||
|
```
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
```python
|
||||||
|
from kwork_api import KworkClient
|
||||||
|
|
||||||
|
# Login with credentials
|
||||||
|
client = await KworkClient.login("username", "password")
|
||||||
|
|
||||||
|
# Or restore from token
|
||||||
|
client = KworkClient(token="your_web_auth_token")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```python
|
||||||
|
async with KworkClient(token="token") as client:
|
||||||
|
# Get catalog
|
||||||
|
catalog = await client.catalog.get_list(page=1)
|
||||||
|
|
||||||
|
# Get kwork details
|
||||||
|
details = await client.catalog.get_details(kwork_id=123)
|
||||||
|
|
||||||
|
# Get projects
|
||||||
|
projects = await client.projects.get_list()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation Sections
|
||||||
|
|
||||||
|
- **[API Reference](api-reference.md)** — All endpoints and methods
|
||||||
|
- **[Models](api-reference.md#models)** — Pydantic models
|
||||||
|
- **[Errors](api-reference.md#errors)** — Exception classes
|
||||||
|
- **[Examples](examples.md)** — Usage examples
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ✅ Full API coverage (45 endpoints)
|
||||||
|
- ✅ Async/await support
|
||||||
|
- ✅ Pydantic models for type safety
|
||||||
|
- ✅ Clear error handling
|
||||||
|
- ✅ Session management
|
||||||
|
|
||||||
|
## Rate Limiting
|
||||||
|
|
||||||
|
Rate limiting is **not** implemented in the library. Handle it in your code:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
for page in range(1, 10):
|
||||||
|
catalog = await client.catalog.get_list(page=page)
|
||||||
|
await asyncio.sleep(1) # 1 second delay
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
```python
|
||||||
|
from kwork_api import KworkAuthError, KworkApiError
|
||||||
|
|
||||||
|
try:
|
||||||
|
catalog = await client.catalog.get_list()
|
||||||
|
except KworkAuthError as e:
|
||||||
|
print(f"Auth failed: {e}")
|
||||||
|
except KworkApiError as e:
|
||||||
|
print(f"API error [{e.status_code}]: {e.message}")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Documentation auto-generated from source code.*
|
||||||
193
scripts/generate_docs.py
Normal file
193
scripts/generate_docs.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Generate API documentation from docstrings.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python scripts/generate_docs.py
|
||||||
|
|
||||||
|
Generates docs/api-reference.md from source code docstrings.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ast
|
||||||
|
import inspect
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
def extract_class_info(class_node: ast.ClassDef, source_lines: List[str]) -> dict:
|
||||||
|
"""Extract class information including docstring and methods."""
|
||||||
|
info = {
|
||||||
|
"name": class_node.name,
|
||||||
|
"docstring": ast.get_docstring(class_node) or "",
|
||||||
|
"methods": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for node in class_node.body:
|
||||||
|
if isinstance(node, ast.FunctionDef) and not node.name.startswith("_"):
|
||||||
|
method_info = {
|
||||||
|
"name": node.name,
|
||||||
|
"docstring": ast.get_docstring(node) or "",
|
||||||
|
"args": [],
|
||||||
|
"returns": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract arguments
|
||||||
|
for arg in node.args.args:
|
||||||
|
if arg.arg not in ("self", "cls"):
|
||||||
|
method_info["args"].append(arg.arg)
|
||||||
|
|
||||||
|
info["methods"].append(method_info)
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def parse_module(file_path: Path) -> List[dict]:
|
||||||
|
"""Parse Python module and extract classes with methods."""
|
||||||
|
source = file_path.read_text()
|
||||||
|
source_lines = source.splitlines()
|
||||||
|
tree = ast.parse(source)
|
||||||
|
|
||||||
|
classes = []
|
||||||
|
for node in ast.walk(tree):
|
||||||
|
if isinstance(node, ast.ClassDef):
|
||||||
|
classes.append(extract_class_info(node, source_lines))
|
||||||
|
|
||||||
|
return classes
|
||||||
|
|
||||||
|
|
||||||
|
def generate_api_reference(src_dir: Path, output_path: Path):
|
||||||
|
"""Generate API reference markdown from source code."""
|
||||||
|
|
||||||
|
# Parse client.py
|
||||||
|
client_path = src_dir / "client.py"
|
||||||
|
classes = parse_module(client_path)
|
||||||
|
|
||||||
|
# Generate markdown
|
||||||
|
md_lines = [
|
||||||
|
"# API Reference",
|
||||||
|
"",
|
||||||
|
"Auto-generated API documentation.",
|
||||||
|
"",
|
||||||
|
"Last updated: " + Path().cwd().name, # Will be updated with date
|
||||||
|
"",
|
||||||
|
"---",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
|
for cls in classes:
|
||||||
|
if not cls["docstring"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
md_lines.append(f"## {cls['name']}")
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append(cls["docstring"])
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
if cls["methods"]:
|
||||||
|
md_lines.append("### Methods")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
for method in cls["methods"]:
|
||||||
|
args_str = ", ".join(method["args"])
|
||||||
|
md_lines.append(f"#### `{method['name']}({args_str})`")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
if method["docstring"]:
|
||||||
|
md_lines.append(method["docstring"])
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
md_lines.append("---")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
# Parse models.py
|
||||||
|
models_path = src_dir / "models.py"
|
||||||
|
if models_path.exists():
|
||||||
|
model_classes = parse_module(models_path)
|
||||||
|
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("# Models")
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("Pydantic models used in API responses.")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
for cls in model_classes:
|
||||||
|
if cls["name"].startswith("_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
md_lines.append(f"## {cls['name']}")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
if cls["docstring"]:
|
||||||
|
md_lines.append(cls["docstring"])
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
# Show fields
|
||||||
|
md_lines.append("### Fields")
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("| Field | Type | Description |")
|
||||||
|
md_lines.append("|-------|------|-------------|")
|
||||||
|
|
||||||
|
# Extract fields from class body
|
||||||
|
for node in ast.walk(ast.parse(models_path.read_text())):
|
||||||
|
if isinstance(node, ast.ClassDef) and node.name == cls["name"]:
|
||||||
|
for item in node.body:
|
||||||
|
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||||
|
field_name = item.target.id
|
||||||
|
if not field_name.startswith("_"):
|
||||||
|
md_lines.append(f"| `{field_name}` | - | - |")
|
||||||
|
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("---")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
# Parse errors.py
|
||||||
|
errors_path = src_dir / "errors.py"
|
||||||
|
if errors_path.exists():
|
||||||
|
error_classes = parse_module(errors_path)
|
||||||
|
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("# Errors")
|
||||||
|
md_lines.append("")
|
||||||
|
md_lines.append("Exception classes for error handling.")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
for cls in error_classes:
|
||||||
|
if cls["name"].startswith("_"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
md_lines.append(f"## {cls['name']}")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
if cls["docstring"]:
|
||||||
|
md_lines.append(cls["docstring"])
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
md_lines.append("---")
|
||||||
|
md_lines.append("")
|
||||||
|
|
||||||
|
# Write output
|
||||||
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
output_path.write_text("\n".join(md_lines))
|
||||||
|
print(f"✅ Generated {output_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point."""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
root_dir = Path(__file__).parent.parent
|
||||||
|
src_dir = root_dir / "src" / "kwork_api"
|
||||||
|
output_path = root_dir / "docs" / "api-reference.md"
|
||||||
|
|
||||||
|
if not src_dir.exists():
|
||||||
|
print(f"❌ Source directory not found: {src_dir}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
generate_api_reference(src_dir, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue
Block a user