# NetOrca SDK

Modern Python SDK for the NetOrca API with full type hints, model objects, and resource-based architecture.

## Features

- **Full Type Hints** - Complete type annotations for better IDE support
- **Model Objects** - Returns typed model objects instead of raw dicts
- **Resource-Based** - Clean, intuitive resource organization
- **Auto-Pagination** - Automatic handling of paginated responses

## Prerequisites

- NetOrca API Key
- URL for the NetOrca API
- Python 3.8+

## Installation

```bash
# From PyPI
pip install netorca-sdk

# From GitLab
pip install git+https://gitlab.com/netorca_public/netorca_sdk.git@v2
```

## Quick Start

```python
from netorca_sdk import NetOrcaClient

# Initialize client
client = NetOrcaClient(
    fqdn="https://api-generaldemo.demo.netorca.io/v1",
    api_key="YOUR_API_KEY"
)

# List service items (with auto-pagination)
for item in client.service_items.list():
    print(f"{item.name}: {item.runtime_state}")

# Get specific item
item = client.service_items.get(123)
print(f"Service: {item.service_name}")
print(f"Application: {item.application_name}")
```

## Client Initialization

### With API Key (Recommended)

```python
client = NetOrcaClient(
    fqdn="https://api-generaldemo.demo.netorca.io/v1",
    api_key="YOUR_API_KEY"
)
```

### With Context

```python
# ServiceOwner context (default)
client = NetOrcaClient(fqdn="...", api_key="...", context="serviceowner")

# Consumer context
client = NetOrcaClient(fqdn="...", api_key="...", context="consumer")
```

## Available Resources

All resources are accessible via the client:

```python
client.services           # Services
client.service_items      # Service Items
client.deployed_items     # Deployed Items
client.change_instances   # Change Instances
client.service_configs    # Service Configs
client.charges            # Charges
client.applications       # Applications
client.submissions        # Submissions
client.healthchecks       # Healthchecks
client.webhooks           # Webhooks
```

## Usage Examples

### Service Items

```python
# List all service items (auto-excludes decommissioned)
for item in client.service_items.list():
    print(item.name, item.runtime_state)

# List with filters
for item in client.service_items.list(service_name="web-app"):
    print(item.name)

# Get items as list instead of generator
items = client.service_items.filter(runtime_state="IN_SERVICE")

# Get specific item
item = client.service_items.get(123)

# Filter by service
items = client.service_items.by_service(service_id=45)

# Filter by application
items = client.service_items.by_application(application_id=78)

# State checks
item = client.service_items.get(123)
if item.is_requested():
    print("Item is requested")
if item.is_in_service():
    print("Item is in service")
```

### Services

```python
# List all services
for service in client.services.list():
    print(service.name, service.state)

# Get specific service
service = client.services.get(45)
print(f"Title: {service.title}")
print(f"Owner: {service.owner_name}")

# Create service
new_service = client.services.create({
    "name": "my-service",
    "title": "My Service",
    "description": "Service description",
    "schema": {...}
})

# Update service
updated = client.services.update(45, {"title": "Updated Title"})

# Delete service
client.services.delete(45)
```

### Deployed Items

```python
# List deployed items
for item in client.deployed_items.list():
    print(item.name, item.state)

# Get specific deployed item
item = client.deployed_items.get(789)

# Create deployed item
new_item = client.deployed_items.create({
    "service_item": 123,
    "change_instance": 456,
    "data": {...}
})
```

### Change Instances

```python
# List change instances
for ci in client.change_instances.list():
    print(ci.id, ci.state, ci.change_type)

# Get specific change instance
ci = client.change_instances.get(456)
print(f"State: {ci.state}")

# Update change instance
updated = client.change_instances.update(456, {"state": "approved"})
```

### Submissions

```python
# List submissions
for submission in client.submissions.list():
    print(submission.status)

# Validate submission
validation = client.submissions.validate({
    "service": 45,
    "declaration": {...}
})

# Submit
result = client.submissions.submit({
    "service": 45,
    "declaration": {...}
})
```

## Working with Models

All models provide clean property access:

```python
item = client.service_items.get(123)

# Access properties
print(item.id)                    # Resource ID
print(item.name)                  # Service item name
print(item.runtime_state)         # Runtime state
print(item.created)               # Datetime object

# Nested objects automatically extracted
print(item.service_id)            # Service ID (from nested object)
print(item.service_name)          # Service name (from nested object)
print(item.application_id)        # Application ID

# Convert to dict
data = item.to_dict()             # Get raw API data
```

## Pagination

The SDK automatically handles pagination:

```python
# Generator-based (memory efficient for large datasets)
for item in client.service_items.list():
    process(item)

# Load all results into memory
all_items = client.service_items.filter()  # Returns list

# Or convert generator to list
all_items = list(client.service_items.list())
```

## Error Handling

```python
from netorca_sdk.v2.exceptions import (
    NetorcaException,
    NetorcaAPIError,
    NetorcaAuthenticationError,
    NetorcaNotFoundError,
)

try:
    item = client.service_items.get(999999)
except NetorcaNotFoundError:
    print("Service item not found")
except NetorcaAPIError as e:
    print(f"API error: {e}")
except NetorcaException as e:
    print(f"General error: {e}")
```

## License

This code is provided under the [MIT License](LICENSE).
