secure-api-py


Namesecure-api-py JSON
Version 2.0.1 PyPI version JSON
download
home_pageNone
SummaryA lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.
upload_time2025-11-09 16:17:23
maintainerNone
docs_urlNone
authorMarcusXTechnologies
requires_python>=3.8
licenseBSD-3-Clause
keywords appwrite api rest framework functions
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # SecureAPI-Py - A Secure RESTful API Framework for Appwrite Functions

**`SecureAPI-Py`** is a lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions using Python. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.

## Table of Contents

- [Features](#features)
- [Installation](#installation)
- [Getting Started](#getting-started)
  - [Core Library](#core-library-secureapi)
  - [Utility Modules](#utility-modules)
  - [Middleware](#middleware)
  - [Real-World Example](#real-world-example)
- [Configuration](#configuration)
- [API Reference](#api-reference)
- [Contributing](#contributing)
- [License](#license)

## Features

- **Core Library**: Simplifies request/response handling, error management, and enhanced logging with pretty-print support.
- **Utility Modules**:
  - **Validator**: Ensures input integrity by validating headers, query parameters, and body content.
  - **Security**: Provides JWT validation and API key verification.
  - **DatabaseManager**: Facilitates CRUD operations on Appwrite databases with flexible database ID management.
- **Enhanced Logging**: Pretty-print JSON/dicts with proper formatting for better debugging.
- **Middleware Support**: Customize request processing with authentication, logging, CORS, and validation middleware.
- **Helper Properties**: Convenient properties for accessing Appwrite Function metadata, user info, and environment variables.
- **Response Types**: Support for all Appwrite Function response types (JSON, text, binary, redirect, empty).
- **Router**: Simple routing system for handling multiple endpoints.

## Installation

To use `SecureAPI-Py` in your Appwrite function, add it to your `requirements.txt` file:

```txt
secure-api-py>=1.0.0
appwrite>=7.0.0
```

Then, install the dependencies:

```bash
pip install -r requirements.txt
```

## Getting Started

### Core Library: `SecureAPI`

#### Usage

The `SecureAPI` class is your entry point to build APIs. It handles request processing and provides utility methods for standardized responses.

#### Example:

```python
from secure_api import SecureAPI

def main(context):
    # Option 1: Initialize with a default database ID
    api = SecureAPI(context, database_id='YOUR_DATABASE_ID')
    
    # Option 2: Initialize without default database ID (flexible approach)
    # api = SecureAPI(context)
    
    if api.context.req.path == '/tasks/create' and api.method == 'POST':
        # Add task creation logic here
        return api.send_success(message='Task created', data=task_doc)
```

### Utility Modules

#### Validator

Ensures your API receives valid input.

```python
from secure_api import Validator

async def input_validator(api):
    Validator.validate_headers(api.headers, ['x-api-key'])
    Validator.validate_query_params(api.query_params, ['type'])
    api.log('Input validation passed.')
```

#### Security

Handle authentication via JWTs or API keys.

```python
from secure_api import Security, auth_middleware

# Use built-in auth middleware
api.use_middleware(auth_middleware)

# Or create custom authentication
async def custom_auth(api):
    headers = api.headers
    
    if 'x-api-key' not in headers or not headers['x-api-key']:
        raise Exception('Missing `x-api-key` header.')
    
    jwt = headers['x-api-key']
    security = Security(api.client)
    
    try:
        is_authenticated = await security.validate_jwt(jwt)
        api.log(f'User authenticated: {is_authenticated}')
    except Exception as e:
        api.error(f'Authentication failed: {e}')
        raise Exception('Invalid or expired token.')
```

#### DatabaseManager

Simplifies CRUD operations for Appwrite collections with flexible database management.

```python
async def create_task(api):
    task_doc = await api.db.create_document(
        collection_id='tasks',
        data=task,
        database_id='YOUR_DATABASE_ID'
    )
    return await api.send_success(message='Task created', data=task_doc)
```

**Key Features:**
- **Flexible Database IDs**: Use different databases dynamically
- **Named Parameters**: Clean, readable function calls
- **Backward Compatibility**: Existing code continues to work via `api.db_helper` (deprecated)

### Enhanced Logging

The improved logging system now properly formats objects and dicts for better debugging:

```python
# Simple logging
api.log('Processing request...')

# Pretty-print JSON objects
api.log_json('User Data', {
    'id': '123',
    'name': 'John Doe',
    'permissions': ['read', 'write'],
})

# Automatic formatting for dicts/lists
api.log({
    'status': 'success',
    'count': 42,
    'items': ['item1', 'item2']
})
# Output will be properly indented JSON
```

### Helper Properties

SecureAPI includes convenient helper properties for common Appwrite Function patterns:

```python
# Request helpers
api.path           # Request path
api.url            # Full URL  
api.host           # Hostname
api.method         # HTTP method

# Authentication helpers
api.user_id         # User ID if authenticated
api.user_jwt        # JWT token if available
api.is_authenticated # Check if user is authenticated

# Function metadata
api.trigger_type    # How function was triggered (http, schedule, event)
api.trigger_event   # Event that triggered the function

# Environment variables with defaults
api.get_env('MY_VAR', default_value='default')
```

### Response Types

Support for all Appwrite Function response types:

```python
# JSON responses
await api.send_success(message='Success', data={...})
await api.send_error(message='Error', status_code=500)

# Other response types
await api.send_empty()                          # 204 No Content
await api.send_text('Plain text', status_code=200)
await api.send_redirect('https://example.com')  # 301 Redirect
await api.send_binary(bytes_data)               # Binary data
```

### Middleware

Middleware functions process requests before hitting route handlers:

#### Built-in Middleware

1. **CORS Middleware**:
```python
from secure_api import cors_middleware

api.use_middleware(cors_middleware(
    origin='*',
    methods='GET, POST, PUT, DELETE, OPTIONS',
    headers='Content-Type, Authorization',
))
```

2. **Logging Request Middleware** (with enhanced formatting):
```python
from secure_api import log_request

api.use_middleware(log_request)  # Now with pretty-print support!
```

3. **Authentication Middleware**:
```python
from secure_api import auth_middleware

api.use_middleware(auth_middleware)
```

4. **Rate Limiting Middleware**:
```python
from secure_api import rate_limit_middleware

api.use_middleware(rate_limit_middleware(
    max_requests=100,
    window_minutes=1
))
```

#### Adding Middleware (Order Matters!)

```python
api.use_middleware(cors_middleware())  # Handle CORS first
api.use_middleware(log_request)        # Then log requests
api.use_middleware(auth_middleware)    # Then check auth
```

### Router

Use the built-in router for handling multiple endpoints:

```python
from secure_api import SecureAPI, Router

async def main(context):
    api = SecureAPI(context, database_id='YOUR_DATABASE_ID')
    router = Router()
    
    # Define routes
    router.get('/tasks', list_tasks)
    router.post('/tasks', create_task)
    router.put('/tasks/:id', update_task)
    router.delete('/tasks/:id', delete_task)
    
    # Execute middleware
    await api.execute_middleware()
    
    # Handle request
    return await router.handle(api)

async def list_tasks(api, params):
    tasks = await api.db.list_documents(collection_id='tasks')
    return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})

async def create_task(api, params):
    api.validate_body({'title': 'required|string', 'description': 'required|string'})
    task = {
        'title': api.body_json['title'],
        'description': api.body_json['description'],
        'completed': False,
    }
    task_doc = await api.db.create_document(collection_id='tasks', data=task)
    return await api.send_success(message='Task created', data=task_doc)

async def update_task(api, params):
    task_id = params['id']
    data = api.body_json
    task_doc = await api.db.update_document(
        collection_id='tasks',
        document_id=task_id,
        data=data
    )
    return await api.send_success(message='Task updated', data=task_doc)

async def delete_task(api, params):
    task_id = params['id']
    await api.db.delete_document(collection_id='tasks', document_id=task_id)
    return await api.send_success(message='Task deleted')
```

### Real-World Example: Task Management System

#### Endpoints

1. **Create Task**: `POST /tasks/create`
2. **List Tasks**: `GET /tasks/get`
3. **Update Task**: `PUT /tasks/update`
4. **Delete Task**: `DELETE /tasks/delete`

#### Example Implementation

```python
from secure_api import SecureAPI, log_request, auth_middleware, Validator

async def main(context):
    # Flexible initialization - can work with or without default database ID
    api = SecureAPI(context)
    
    # Middleware
    api.use_middleware(log_request)
    api.use_middleware(auth_middleware)
    
    # Handle requests
    try:
        await api.execute_middleware()
        path = api.context.req.path
        
        if path == '/tasks/create' and api.method == 'POST':
            return await create_task(api)
        elif path == '/tasks/get' and api.method == 'GET':
            return await list_tasks(api)
        elif path == '/tasks/update' and api.method == 'PUT':
            return await update_task(api)
        elif path == '/tasks/delete' and api.method == 'DELETE':
            return await delete_task(api)
        else:
            return await api.send_error(
                message='Endpoint not found',
                status_code=404,
            )
    except Exception as e:
        api.error(f'Error: {e}')
        return await api.handle_error(e)

async def create_task(api):
    Validator.validate_body(api.body_json, ['title', 'description'])
    task = {
        'title': api.body_json['title'],
        'description': api.body_json['description'],
        'completed': False,
    }
    
    task_doc = await api.db.create_document(
        collection_id='tasks',
        data=task,
        database_id='YOUR_DATABASE_ID'
    )
    return await api.send_success(message='Task created', data=task_doc)

async def list_tasks(api):
    tasks = await api.db.list_documents(
        collection_id='tasks',
        database_id='YOUR_DATABASE_ID'
    )
    return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})
```

## Configuration

Configure your Appwrite function to use `SecureAPI-Py` by setting up the necessary environment variables and dependencies as described in the [Getting Started](#getting-started) section.

## API Reference

### SecureAPI Class

Main class for handling requests and responses.

**Methods:**
- `log(message)` - Log a message
- `error(message)` - Log an error
- `log_json(label, data)` - Log JSON with label
- `send_success(...)` - Send success response
- `send_error(...)` - Send error response
- `send_unauthorized(...)` - Send 401 response
- `send_empty()` - Send 204 response
- `send_redirect(url)` - Send redirect response
- `send_text(text)` - Send text response
- `send_binary(bytes)` - Send binary response
- `validate_body(rules)` - Validate request body
- `handle_error(error)` - Handle errors

**Properties:**
- `method` - HTTP method
- `headers` - Request headers
- `query_params` - Query parameters
- `body_text` - Request body as text
- `body_json` - Request body as JSON
- `path` - Request path
- `url` - Request URL
- `user_id` - Authenticated user ID
- `is_authenticated` - Authentication status

## Contributing

Contributions are welcome! Please submit pull requests or open issues for suggestions.

## License

This package is distributed under the BSD-3-Clause License.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "secure-api-py",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "appwrite, api, rest, framework, functions",
    "author": "MarcusXTechnologies",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/45/61/5ca25c2d2069ea0cbf437217fbb65391fe7c0778b7734fd4b552f3e10b63/secure_api_py-2.0.1.tar.gz",
    "platform": null,
    "description": "# SecureAPI-Py - A Secure RESTful API Framework for Appwrite Functions\n\n**`SecureAPI-Py`** is a lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions using Python. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.\n\n## Table of Contents\n\n- [Features](#features)\n- [Installation](#installation)\n- [Getting Started](#getting-started)\n  - [Core Library](#core-library-secureapi)\n  - [Utility Modules](#utility-modules)\n  - [Middleware](#middleware)\n  - [Real-World Example](#real-world-example)\n- [Configuration](#configuration)\n- [API Reference](#api-reference)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Features\n\n- **Core Library**: Simplifies request/response handling, error management, and enhanced logging with pretty-print support.\n- **Utility Modules**:\n  - **Validator**: Ensures input integrity by validating headers, query parameters, and body content.\n  - **Security**: Provides JWT validation and API key verification.\n  - **DatabaseManager**: Facilitates CRUD operations on Appwrite databases with flexible database ID management.\n- **Enhanced Logging**: Pretty-print JSON/dicts with proper formatting for better debugging.\n- **Middleware Support**: Customize request processing with authentication, logging, CORS, and validation middleware.\n- **Helper Properties**: Convenient properties for accessing Appwrite Function metadata, user info, and environment variables.\n- **Response Types**: Support for all Appwrite Function response types (JSON, text, binary, redirect, empty).\n- **Router**: Simple routing system for handling multiple endpoints.\n\n## Installation\n\nTo use `SecureAPI-Py` in your Appwrite function, add it to your `requirements.txt` file:\n\n```txt\nsecure-api-py>=1.0.0\nappwrite>=7.0.0\n```\n\nThen, install the dependencies:\n\n```bash\npip install -r requirements.txt\n```\n\n## Getting Started\n\n### Core Library: `SecureAPI`\n\n#### Usage\n\nThe `SecureAPI` class is your entry point to build APIs. It handles request processing and provides utility methods for standardized responses.\n\n#### Example:\n\n```python\nfrom secure_api import SecureAPI\n\ndef main(context):\n    # Option 1: Initialize with a default database ID\n    api = SecureAPI(context, database_id='YOUR_DATABASE_ID')\n    \n    # Option 2: Initialize without default database ID (flexible approach)\n    # api = SecureAPI(context)\n    \n    if api.context.req.path == '/tasks/create' and api.method == 'POST':\n        # Add task creation logic here\n        return api.send_success(message='Task created', data=task_doc)\n```\n\n### Utility Modules\n\n#### Validator\n\nEnsures your API receives valid input.\n\n```python\nfrom secure_api import Validator\n\nasync def input_validator(api):\n    Validator.validate_headers(api.headers, ['x-api-key'])\n    Validator.validate_query_params(api.query_params, ['type'])\n    api.log('Input validation passed.')\n```\n\n#### Security\n\nHandle authentication via JWTs or API keys.\n\n```python\nfrom secure_api import Security, auth_middleware\n\n# Use built-in auth middleware\napi.use_middleware(auth_middleware)\n\n# Or create custom authentication\nasync def custom_auth(api):\n    headers = api.headers\n    \n    if 'x-api-key' not in headers or not headers['x-api-key']:\n        raise Exception('Missing `x-api-key` header.')\n    \n    jwt = headers['x-api-key']\n    security = Security(api.client)\n    \n    try:\n        is_authenticated = await security.validate_jwt(jwt)\n        api.log(f'User authenticated: {is_authenticated}')\n    except Exception as e:\n        api.error(f'Authentication failed: {e}')\n        raise Exception('Invalid or expired token.')\n```\n\n#### DatabaseManager\n\nSimplifies CRUD operations for Appwrite collections with flexible database management.\n\n```python\nasync def create_task(api):\n    task_doc = await api.db.create_document(\n        collection_id='tasks',\n        data=task,\n        database_id='YOUR_DATABASE_ID'\n    )\n    return await api.send_success(message='Task created', data=task_doc)\n```\n\n**Key Features:**\n- **Flexible Database IDs**: Use different databases dynamically\n- **Named Parameters**: Clean, readable function calls\n- **Backward Compatibility**: Existing code continues to work via `api.db_helper` (deprecated)\n\n### Enhanced Logging\n\nThe improved logging system now properly formats objects and dicts for better debugging:\n\n```python\n# Simple logging\napi.log('Processing request...')\n\n# Pretty-print JSON objects\napi.log_json('User Data', {\n    'id': '123',\n    'name': 'John Doe',\n    'permissions': ['read', 'write'],\n})\n\n# Automatic formatting for dicts/lists\napi.log({\n    'status': 'success',\n    'count': 42,\n    'items': ['item1', 'item2']\n})\n# Output will be properly indented JSON\n```\n\n### Helper Properties\n\nSecureAPI includes convenient helper properties for common Appwrite Function patterns:\n\n```python\n# Request helpers\napi.path           # Request path\napi.url            # Full URL  \napi.host           # Hostname\napi.method         # HTTP method\n\n# Authentication helpers\napi.user_id         # User ID if authenticated\napi.user_jwt        # JWT token if available\napi.is_authenticated # Check if user is authenticated\n\n# Function metadata\napi.trigger_type    # How function was triggered (http, schedule, event)\napi.trigger_event   # Event that triggered the function\n\n# Environment variables with defaults\napi.get_env('MY_VAR', default_value='default')\n```\n\n### Response Types\n\nSupport for all Appwrite Function response types:\n\n```python\n# JSON responses\nawait api.send_success(message='Success', data={...})\nawait api.send_error(message='Error', status_code=500)\n\n# Other response types\nawait api.send_empty()                          # 204 No Content\nawait api.send_text('Plain text', status_code=200)\nawait api.send_redirect('https://example.com')  # 301 Redirect\nawait api.send_binary(bytes_data)               # Binary data\n```\n\n### Middleware\n\nMiddleware functions process requests before hitting route handlers:\n\n#### Built-in Middleware\n\n1. **CORS Middleware**:\n```python\nfrom secure_api import cors_middleware\n\napi.use_middleware(cors_middleware(\n    origin='*',\n    methods='GET, POST, PUT, DELETE, OPTIONS',\n    headers='Content-Type, Authorization',\n))\n```\n\n2. **Logging Request Middleware** (with enhanced formatting):\n```python\nfrom secure_api import log_request\n\napi.use_middleware(log_request)  # Now with pretty-print support!\n```\n\n3. **Authentication Middleware**:\n```python\nfrom secure_api import auth_middleware\n\napi.use_middleware(auth_middleware)\n```\n\n4. **Rate Limiting Middleware**:\n```python\nfrom secure_api import rate_limit_middleware\n\napi.use_middleware(rate_limit_middleware(\n    max_requests=100,\n    window_minutes=1\n))\n```\n\n#### Adding Middleware (Order Matters!)\n\n```python\napi.use_middleware(cors_middleware())  # Handle CORS first\napi.use_middleware(log_request)        # Then log requests\napi.use_middleware(auth_middleware)    # Then check auth\n```\n\n### Router\n\nUse the built-in router for handling multiple endpoints:\n\n```python\nfrom secure_api import SecureAPI, Router\n\nasync def main(context):\n    api = SecureAPI(context, database_id='YOUR_DATABASE_ID')\n    router = Router()\n    \n    # Define routes\n    router.get('/tasks', list_tasks)\n    router.post('/tasks', create_task)\n    router.put('/tasks/:id', update_task)\n    router.delete('/tasks/:id', delete_task)\n    \n    # Execute middleware\n    await api.execute_middleware()\n    \n    # Handle request\n    return await router.handle(api)\n\nasync def list_tasks(api, params):\n    tasks = await api.db.list_documents(collection_id='tasks')\n    return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})\n\nasync def create_task(api, params):\n    api.validate_body({'title': 'required|string', 'description': 'required|string'})\n    task = {\n        'title': api.body_json['title'],\n        'description': api.body_json['description'],\n        'completed': False,\n    }\n    task_doc = await api.db.create_document(collection_id='tasks', data=task)\n    return await api.send_success(message='Task created', data=task_doc)\n\nasync def update_task(api, params):\n    task_id = params['id']\n    data = api.body_json\n    task_doc = await api.db.update_document(\n        collection_id='tasks',\n        document_id=task_id,\n        data=data\n    )\n    return await api.send_success(message='Task updated', data=task_doc)\n\nasync def delete_task(api, params):\n    task_id = params['id']\n    await api.db.delete_document(collection_id='tasks', document_id=task_id)\n    return await api.send_success(message='Task deleted')\n```\n\n### Real-World Example: Task Management System\n\n#### Endpoints\n\n1. **Create Task**: `POST /tasks/create`\n2. **List Tasks**: `GET /tasks/get`\n3. **Update Task**: `PUT /tasks/update`\n4. **Delete Task**: `DELETE /tasks/delete`\n\n#### Example Implementation\n\n```python\nfrom secure_api import SecureAPI, log_request, auth_middleware, Validator\n\nasync def main(context):\n    # Flexible initialization - can work with or without default database ID\n    api = SecureAPI(context)\n    \n    # Middleware\n    api.use_middleware(log_request)\n    api.use_middleware(auth_middleware)\n    \n    # Handle requests\n    try:\n        await api.execute_middleware()\n        path = api.context.req.path\n        \n        if path == '/tasks/create' and api.method == 'POST':\n            return await create_task(api)\n        elif path == '/tasks/get' and api.method == 'GET':\n            return await list_tasks(api)\n        elif path == '/tasks/update' and api.method == 'PUT':\n            return await update_task(api)\n        elif path == '/tasks/delete' and api.method == 'DELETE':\n            return await delete_task(api)\n        else:\n            return await api.send_error(\n                message='Endpoint not found',\n                status_code=404,\n            )\n    except Exception as e:\n        api.error(f'Error: {e}')\n        return await api.handle_error(e)\n\nasync def create_task(api):\n    Validator.validate_body(api.body_json, ['title', 'description'])\n    task = {\n        'title': api.body_json['title'],\n        'description': api.body_json['description'],\n        'completed': False,\n    }\n    \n    task_doc = await api.db.create_document(\n        collection_id='tasks',\n        data=task,\n        database_id='YOUR_DATABASE_ID'\n    )\n    return await api.send_success(message='Task created', data=task_doc)\n\nasync def list_tasks(api):\n    tasks = await api.db.list_documents(\n        collection_id='tasks',\n        database_id='YOUR_DATABASE_ID'\n    )\n    return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})\n```\n\n## Configuration\n\nConfigure your Appwrite function to use `SecureAPI-Py` by setting up the necessary environment variables and dependencies as described in the [Getting Started](#getting-started) section.\n\n## API Reference\n\n### SecureAPI Class\n\nMain class for handling requests and responses.\n\n**Methods:**\n- `log(message)` - Log a message\n- `error(message)` - Log an error\n- `log_json(label, data)` - Log JSON with label\n- `send_success(...)` - Send success response\n- `send_error(...)` - Send error response\n- `send_unauthorized(...)` - Send 401 response\n- `send_empty()` - Send 204 response\n- `send_redirect(url)` - Send redirect response\n- `send_text(text)` - Send text response\n- `send_binary(bytes)` - Send binary response\n- `validate_body(rules)` - Validate request body\n- `handle_error(error)` - Handle errors\n\n**Properties:**\n- `method` - HTTP method\n- `headers` - Request headers\n- `query_params` - Query parameters\n- `body_text` - Request body as text\n- `body_json` - Request body as JSON\n- `path` - Request path\n- `url` - Request URL\n- `user_id` - Authenticated user ID\n- `is_authenticated` - Authentication status\n\n## Contributing\n\nContributions are welcome! Please submit pull requests or open issues for suggestions.\n\n## License\n\nThis package is distributed under the BSD-3-Clause License.\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "A lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.",
    "version": "2.0.1",
    "project_urls": {
        "Homepage": "https://github.com/mj-963/secure_api_py",
        "Issues": "https://github.com/mj-963/secure_api_py/issues",
        "Repository": "https://github.com/mj-963/secure_api_py"
    },
    "split_keywords": [
        "appwrite",
        " api",
        " rest",
        " framework",
        " functions"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0136bef140952955599e9e0708f3c13948bb5bad0ac5546f6d51ee9ca24b6761",
                "md5": "39aaa12b628a27e7e60472fbe559ccd0",
                "sha256": "f6e018e5c085f89e3c0c4f9085e3a5fecdf02bce02d832f6509f519069367356"
            },
            "downloads": -1,
            "filename": "secure_api_py-2.0.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "39aaa12b628a27e7e60472fbe559ccd0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 23205,
            "upload_time": "2025-11-09T16:17:21",
            "upload_time_iso_8601": "2025-11-09T16:17:21.481043Z",
            "url": "https://files.pythonhosted.org/packages/01/36/bef140952955599e9e0708f3c13948bb5bad0ac5546f6d51ee9ca24b6761/secure_api_py-2.0.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "45615ca25c2d2069ea0cbf437217fbb65391fe7c0778b7734fd4b552f3e10b63",
                "md5": "66cd70007389c0b67c6107839db3c966",
                "sha256": "eae2553735a0dda23df4ada9b1199287f9ab4be01e07bb6cb2125ffcc5bbae05"
            },
            "downloads": -1,
            "filename": "secure_api_py-2.0.1.tar.gz",
            "has_sig": false,
            "md5_digest": "66cd70007389c0b67c6107839db3c966",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 24763,
            "upload_time": "2025-11-09T16:17:23",
            "upload_time_iso_8601": "2025-11-09T16:17:23.476542Z",
            "url": "https://files.pythonhosted.org/packages/45/61/5ca25c2d2069ea0cbf437217fbb65391fe7c0778b7734fd4b552f3e10b63/secure_api_py-2.0.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-09 16:17:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mj-963",
    "github_project": "secure_api_py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "secure-api-py"
}
        
Elapsed time: 1.20204s