Skip to main content

Python ScanUpload API Client for seamless integration into ScanUpload SAAS product

Project description

ScanUpload API Client - Python Integration Guide

ScanUpload enables the integration and the ability to use QR codes to scan and upload files directly from a mobile device to your webapp.

This guide explains how to integrate scan-upload-api-client into a Python application. The client library requires Python 3.11+ and is compatible with:

  • FastAPI
  • Starlette
  • Django (with async views)
  • Flask (with async support)
  • Any ASGI application

Prerequisites

Installation

pip install scan-upload-api-client

If you want to pin to a specific release:

pip install scan-upload-api-client==1.0.0

For ASGI/web framework integration:

pip install scan-upload-api-client[asgi]

Configuration

Configure using environment variables or a .env file:

SCANUPLOAD_TARGET_BASE_URL=https://hub.scanupload.net/api/front-end
SCANUPLOAD_ROUTE_PREFIX=/scanupload-api
SCANUPLOAD_TOKEN_ROUTE=/scanupload-api/token
SCANUPLOAD_STRIP_ROUTE_PREFIX=true
SCANUPLOAD_REQUEST_TIMEOUT=90

SCANUPLOAD_API_CLIENT_BASE_URL=https://hub.scanupload.net

KEYCLOAK_SERVER_URL=https://identity.scanupload.net/
KEYCLOAK_REALM=scanupload-hub
KEYCLOAK_CLIENT_ID=your-client-id
KEYCLOAK_CLIENT_SECRET=your-client-secret
KEYCLOAK_SCOPE=openid profile email scanupload.hub

# Optional: enable HTTPS for FastAPI example
UVICORN_SSL_CERTFILE=C:/path/to/localhost.pem
UVICORN_SSL_KEYFILE=C:/path/to/localhost-key.pem

The example apps in examples/ load configuration in this order:

  1. SCANUPLOAD_DOTENV_PATH (if set)
  2. .env in the current working directory
  3. .env in the repository root
  4. Terminal environment variables

WARNING: Never commit secrets to source control. Use environment variables or a secrets management system.

Basic Usage

Keycloak Token Client

import asyncio
from scan_upload_api_client import KeycloakClient, ScanUploadProxyOptions

async def main():
    options = ScanUploadProxyOptions(
        keycloak_server_url="https://identity.scanupload.net/",
        keycloak_realm="scanupload-hub",
        keycloak_client_id="your-client-id",
        keycloak_client_secret="your-client-secret",
    )

    async with KeycloakClient(options) as client:
        token = await client.get_client_credentials_token()
        print(f"Access token: {token.access_token}")

asyncio.run(main())

Token Provider with Caching

from scan_upload_api_client import TokenProvider, KeycloakClient, ScanUploadProxyOptions

async def main():
    options = ScanUploadProxyOptions(
        keycloak_server_url="https://identity.scanupload.net/",
        keycloak_realm="scanupload-hub",
        keycloak_client_id="your-client-id",
        keycloak_client_secret="your-client-secret",
        keycloak_early_refresh_seconds=120,
    )

    async with KeycloakClient(options) as keycloak_client:
        provider = TokenProvider(keycloak_client, options)

        # First call fetches token
        token1 = await provider.get_access_token()

        # Second call uses cache
        token2 = await provider.get_access_token()

        assert token1.access_token == token2.access_token

asyncio.run(main())

Download Files

from scan_upload_api_client import ScanUploadApiClient, TokenProvider

async def main():
    # Setup token provider...
    api_client = ScanUploadApiClient(
        base_url="https://hub.scanupload.net",
        token_provider=provider,
    )

    async def process_file(filename: str, content: bytes):
        print(f"Processing {filename} ({len(content)} bytes)")
        # Save or process file content

    await api_client.download_async("session-id-123", process_file)

asyncio.run(main())

Framework Integration

If you are consuming the package from PyPI, install the ASGI extras first:

pip install "scan-upload-api-client[asgi]"

Then create your FastAPI app with the published package:

from fastapi import FastAPI
from contextlib import asynccontextmanager
from scan_upload_api_client import (
    KeycloakClient,
    ScanUploadProxyOptions,
    TokenProvider,
)
from scan_upload_api_client.middleware import ScanUploadProxyMiddleware

options = ScanUploadProxyOptions(
    target_base_url="https://hub.scanupload.net/api/front-end",
    route_prefix="/scanupload-api",
    token_route="/scanupload-api/token",
    strip_route_prefix=True,
    keycloak_server_url="https://identity.scanupload.net/",
    keycloak_realm="scanupload-hub",
    keycloak_client_id="your-client-id",
    keycloak_client_secret="your-client-secret",
)

@asynccontextmanager
async def lifespan(app: FastAPI):
    keycloak_client = KeycloakClient(options)
    token_provider = TokenProvider(keycloak_client, options)
    app.state.scan_upload_token_provider = token_provider
    try:
        yield
    finally:
        await keycloak_client.close()

app = FastAPI(title="ScanUpload FastAPI Example", lifespan=lifespan)
app.add_middleware(ScanUploadProxyMiddleware, options=options)

@app.get("/")
async def root():
    return {"message": "ScanUpload API client is active"}

The reusable repository example in examples/fastapi_example.py follows the same pattern, adds /token and /download/{session_id} helper routes, and can be adapted directly into an existing FastAPI service.

You can also integrate the middleware in Starlette:

from contextlib import asynccontextmanager

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

from scan_upload_api_client import (
    KeycloakClient,
    ScanUploadProxyOptions,
    TokenProvider,
)
from scan_upload_api_client.middleware import ScanUploadProxyMiddleware

options = ScanUploadProxyOptions(
    target_base_url="https://hub.scanupload.net/api/front-end",
    route_prefix="/scanupload-api",
    token_route="/scanupload-api/token",
    strip_route_prefix=True,
    keycloak_server_url="https://identity.scanupload.net/",
    keycloak_realm="scanupload-hub",
    keycloak_client_id="your-client-id",
    keycloak_client_secret="your-client-secret",
)

async def root(_):
    return JSONResponse({"message": "ScanUpload API client is active"})

@asynccontextmanager
async def lifespan(app: Starlette):
    keycloak_client = KeycloakClient(options)
    token_provider = TokenProvider(keycloak_client, options)
    app.state.scan_upload_token_provider = token_provider
    try:
        yield
    finally:
        await keycloak_client.close()

app = Starlette(routes=[Route("/", root)], lifespan=lifespan)
app.add_middleware(ScanUploadProxyMiddleware, options=options)

The reusable repository example in examples/starlette_example.py follows the same pattern, adds /health, /token, and /download/{session_id} helper routes, and can be adapted directly into an existing Starlette service.

To run the full FastAPI example app from this repository:

pip install -e .[asgi]
python examples/fastapi_example.py

To run the full Starlette example app from this repository:

pip install -e .[asgi]
python examples/starlette_example.py

By default, the example runs on http://localhost:7021. If both UVICORN_SSL_CERTFILE and UVICORN_SSL_KEYFILE are set, it runs on https://localhost:7021.

Running Tests

# Install test dependencies
pip install -e .[test]

# Run tests
pytest

Compatibility Notes

  • Requires Python 3.11+
  • Fully async (uses httpx.AsyncClient)
  • Thread-safe token caching
  • Compatible with FastAPI, Starlette, Django, Flask

License

See the repository license file for terms.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

scan_upload_api_client-1.0.2.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

scan_upload_api_client-1.0.2-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file scan_upload_api_client-1.0.2.tar.gz.

File metadata

  • Download URL: scan_upload_api_client-1.0.2.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for scan_upload_api_client-1.0.2.tar.gz
Algorithm Hash digest
SHA256 9ca5a4c978251a850927f3e84265af3c418d2fc9965cfb20fa56ba98079d506b
MD5 6b9f3f8318a00d4d6e95ac68ecb8dfb2
BLAKE2b-256 c3c2bc819dc0f0b8c48b7aee47cb00184cf56a3a8cab589e9ecd1ccff45d59ac

See more details on using hashes here.

File details

Details for the file scan_upload_api_client-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for scan_upload_api_client-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 42d40b860f617d5d90bd3d86998c6355c10e697e0021232011011da1cea50ae2
MD5 7040c0787cfb74b186bdff0106d855ff
BLAKE2b-256 fc3b067cec554f6da8aedd6f9dd19d3c170c087ffddc796de23727f78c1937ba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page