Skip to content
Projects

hajdu-patrik/3D-Printer-Slicer-API

View on GitHub

hajdu-patrik/3D-Printer-Slicer-API has 44 GitHub stars and 5 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-14 23:55 UTC. Last push 2026-09-25.

How these counts are measured

What you can do

  • 🔄 Model-focused input processing: direct 3D, CAD, and ZIP uploads with exactly one supported model source file.
  • ⚖️ Auto-orientation: Python-based orientation optimization before slicing.
  • 🧮 Pricing engine: dynamic hourly-rate calculation from persisted pricing map.
  • 🚦 Queue + rate protection: bounded queue and endpoint rate limiting for CPU-heavy requests.

Measured star growth

in 24h
0
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

About

An automated 3D slicing and pricing API built with Node.js and Python that seamlessly converts various 2D and 3D file formats (including CAD, images, and vectors) into ready-to-print models using PrusaSlicer or OrcaSlicer by your choice. It provides automated part orientation, slicing, and cost estimation for both FDM and SLA printing technologies.

Productivity

README.md

Original

3D Printer Slicer API (FDM & SLA)

3D Printer Slicer API logo

Node.js Express Python PrusaSlicer OrcaSlicer Docker Ubuntu Next API License

An automated 3D slicing and pricing API built with Node.js and Python that converts supported 3D model and CAD inputs into printable outputs with validated pricing.

Built for zero-downtime rollout, this API now supports two slicer engines through separate public endpoints.


✨ Core Features

  • 🔄 Model-focused input processing: direct 3D, CAD, and ZIP uploads with exactly one supported model source file.
  • ⚖️ Auto-orientation: Python-based orientation optimization before slicing.
  • 🧮 Pricing engine: dynamic hourly-rate calculation from persisted pricing map.
  • 🚦 Queue + rate protection: bounded queue and endpoint rate limiting for CPU-heavy requests.
  • 🧨 ZIP safety checks: entry/size/path validation and encrypted ZIP rejection.
  • 🧵 Dual slicer routing: Prusa and Orca engines behind dedicated endpoints.

📂 Supported File Formats

Category Extensions
Direct 3D .stl, .obj, .3mf
NURBS / CAD .stp, .step, .igs, .iges, .ply
Archive .zip

🔑 Authentication

Admin-protected endpoints require:

  • Header: x-api-key: <ADMIN_API_KEY>

Public endpoints do not require admin key.


🌐 Endpoints

Public

  • GET /health
  • GET /pricing
  • POST /prusa/slice
  • POST /orca/slice
  • GET /openapi.json
  • GET /docs
  • GET /

Admin-protected

  • GET /health/detailed
  • POST /pricing/FDM
  • POST /pricing/SLA
  • PATCH /pricing/:technology/:material
  • DELETE /pricing/:technology/:material
  • GET /admin/output-files
  • GET /admin/download/:fileName

📂 Application Module Map (app/*.js)

Bootstrap

  • app/server.js - Express bootstrap, startup guards, helmet/cors, request-id propagation, docs mounting, routes, and global error handling.

Configuration

  • app/config/constants.js - runtime defaults, layer presets, limits, and extension groups.
  • app/config/paths.js - root-scoped runtime path resolution (input/, output/, configs/) and directory creation.
  • app/config/python.js - secure Python executable resolver (PYTHON_EXECUTABLE + VIRTUAL_ENV fallbacks).

Middleware

  • app/middleware/rateLimit.js - in-memory IP throttling for slice and admin routes (Retry-After aware responses).
  • app/middleware/requireAdmin.js - timing-safe x-api-key guard + unauthorized attempt logging.
  • app/middleware/errorHandler.js - centralized request/upload/parser error normalization.

Routes

  • app/routes/slice.routes.js - POST /prusa/slice, POST /orca/slice with rate-limit and single-file upload middleware.
  • app/routes/pricing.routes.js - public pricing read + admin pricing mutations.
  • app/routes/system.routes.js - health endpoints and admin artifact listing/download endpoints.

Services

  • app/services/pricing.service.js - pricing load/save/migration/lookup logic.
  • app/services/pricing/catalog.js - in-memory pricing catalog: normalization, material lookup, and rate calculation.
  • app/services/pricing/repository.js - file-system pricing repository with primary/legacy pricing file resolution.
  • app/services/admin-output.service.js - validated admin output listing/download helpers and ALL ZIP bulk limit checks.
  • app/services/slice.service.js - end-to-end slicing orchestrator and queue error mapping.
  • app/services/slice/command.js - subprocess execution via execFile with timeout and optional debug logs.
  • app/services/slice/common.js - output naming, isolated Orca output dirs, cleanup utilities.
  • app/services/slice/engine.js - slicer argument construction (Prusa vs Orca).
  • app/services/slice/errors.js - error classification and API error responses.
  • app/services/slice/input-processing.js - conversion/orientation preprocessing pipeline.
  • app/services/slice/model-stats.js - metadata/stat parsing from slicer outputs.
  • app/services/slice/number-utils.js - shared numeric parser helpers.
  • app/services/slice/options.js - strict request option validation/parsing.
  • app/services/slice/profiles.js - profile selection, runtime profile generation, build-volume limits.
  • app/services/slice/queue.js - FIFO queue + per-client fairness + timeout enforcement.
  • app/services/slice/response.js - successful slice response composition and price calculation strategies.
  • app/services/slice/transform.js - transform planning/execution and bounds validation.
  • app/services/slice/value-parsers.js - safe parsing and profile filename sanitization.
  • app/services/slice/zip.js - ZIP safety inspection and safe extraction.

Utilities and API docs

  • app/utils/client-ip.js - trust-proxy-aware client IP normalization.
  • app/utils/logger.js - structured processing error logging.
  • app/docs/swagger-docs.js - OpenAPI generation for /docs and /openapi.json.

🧠 Slicing API Behavior

Both slicing endpoints accept multipart/form-data with required file field:

  • choosenFile

Optional fields:

  • layerHeight
  • material
  • infill (0-100)
  • sizeUnit (mm or inch)
  • keepProportions (true/false, default true)
  • targetSizeX, targetSizeY, targetSizeZ (target dimensions in selected unit)
  • scalePercent (uniform scale; cannot be combined with targetSizeX/Y/Z)
  • rotationX, rotationY, rotationZ (degrees)
  • printerProfile (profile override filename)
  • processProfile (Orca only process profile override filename)

POST /prusa/slice

Uses prusa-slicer.

  • Auto-selects technology by layerHeight:
    • 0.025, 0.05 → SLA
    • 0.1, 0.2, 0.3 → FDM
  • Rejects invalid layerHeight values outside 0.025, 0.05, 0.1, 0.2, 0.3
  • Validates material/technology compatibility
  • Supports size preprocessing before slicing:
    • mm/inch target dimensions
    • aspect-ratio lock (keepProportions=true)
    • free X/Y/Z sizing (keepProportions=false)
    • optional X/Y/Z rotation
  • Validates final model size against selected printer profile limits (min/max build volume)
  • You can override profile file with printerProfile from configs/prusa

Example:

curl -X POST http://localhost:3000/prusa/slice \
  -H "Accept: application/json" \
  -F "choosenFile=@/path/to/model.stl" \
  -F "layerHeight=0.2" \
  -F "material=PLA" \
  -F "infill=20" \
  -F "sizeUnit=mm" \
  -F "keepProportions=true" \
  -F "targetSizeZ=120"

POST /orca/slice

Uses orca-slicer.

  • Forced FDM processing
  • Allowed layerHeight: 0.1, 0.2, 0.3
  • Rejects SLA-only materials
  • Runs with Orca arrange/orient flow and machine+process profile pair
    • Machine profile file is resolved from .env via ORCA_MACHINE_PROFILE (default: Bambu_P1S_0.4_nozzle.json)
  • Process profile file is selected by layerHeight (0.1/0.2/0.3) and can be overridden via .env:
    • ORCA_PROCESS_PROFILE_0_1
    • ORCA_PROCESS_PROFILE_0_2
    • ORCA_PROCESS_PROFILE_0_3
  • Request-level profile overrides are supported:
    • printerProfile → machine profile from configs/orca
    • processProfile → process profile from configs/orca
  • Output artifacts are resolved through a per-request isolated output directory before final filename alignment.
  • Supports same size preprocessing options as Prusa endpoint (sizeUnit, keepProportions, targetSizeX/Y/Z, scalePercent, rotations)
  • Validates final model size against selected machine profile build-volume limits

Example:

curl -X POST http://localhost:3000/orca/slice \
  -H "Accept: application/json" \
  -F "choosenFile=@/path/to/model.stl" \
  -F "layerHeight=0.2" \
  -F "material=PLA" \
  -F "infill=20" \
  -F "printerProfile=Bambu_P1S_0.4_nozzle.json" \
  -F "processProfile=FDM_0.2mm.json" \
  -F "sizeUnit=inch" \
  -F "keepProportions=false" \
  -F "targetSizeX=8.0" \
  -F "targetSizeY=8.0" \
  -F "targetSizeZ=5.0"

Common successful response

{
  "success": true,
  "slicer_engine": "prusa",
  "technology": "FDM",
  "material": "PLA",
  "infill": "20%",
  "profiles": {
    "prusa_profile": "FDM_0.2mm.ini"
  },
  "model_transform": {
    "size_unit": "mm",
    "keep_proportions": true,
    "requested_size": {
      "x": null,
      "y": null,
      "z": 120
    },
    "scale_percent": null,
    "scale_factors": {
      "x": 1.5,
      "y": 1.5,
      "z": 1.5
    },
    "rotation_deg": {
      "x": 0,
      "y": 0,
      "z": 0
    },
    "original_dimensions_mm": {
      "x": 80,
      "y": 60,
      "z": 80
    },
    "final_dimensions_mm": {
      "x": 120,
      "y": 90,
      "z": 120
    }
  },
  "build_volume_limits_mm": {
    "min": {
      "x": 1,
      "y": 1,
      "z": 1
    },
    "max": {
      "x": 256,
      "y": 256,
      "z": 210
    },
    "source_profile": "FDM_0.2mm.ini"
  },
  "hourly_rate": 800,
  "stats": {
    "print_time_seconds": 5400,
    "print_time_readable": "1h 30m",
    "material_used_m": 12.45,
    "object_height_mm": 45.2,
    "estimated_price_huf": 1350
  }
}

Common slicing error codes

  • INVALID_LAYER_HEIGHT
  • INVALID_LAYER_HEIGHT_FOR_ENGINE
  • INVALID_LAYER_HEIGHT_FOR_TECHNOLOGY
  • INVALID_MATERIAL_FOR_TECHNOLOGY
  • MATERIAL_TECHNOLOGY_MISMATCH
  • RATE_LIMIT_EXCEEDED
  • ADMIN_RATE_LIMIT_EXCEEDED
  • INVALID_SOURCE_ARCHIVE
  • INVALID_SOURCE_GEOMETRY
  • UNSUPPORTED_FILE_FORMAT
  • ORCA_PROFILE_INCOMPATIBLE
  • INVALID_SIZE_UNIT
  • INVALID_KEEP_PROPORTIONS
  • INVALID_SIZE_OPTIONS
  • INVALID_ROTATION_OPTIONS
  • CONFLICTING_SIZE_OPTIONS
  • INVALID_PROFILE_NAME
  • PROFILE_NOT_FOUND
  • MODEL_DIMENSIONS_UNAVAILABLE
  • MODEL_OUT_OF_PRINTER_BOUNDS
  • FILE_PROCESSING_TIMEOUT
  • SLICE_QUEUE_FULL
  • SLICE_QUEUE_CLIENT_LIMIT
  • SLICE_QUEUE_TIMEOUT
  • QUEUE_INTERNAL_ERROR
  • INTERNAL_PROCESSING_ERROR

Queue and rate-limit response semantics

  • RATE_LIMIT_EXCEEDED -> HTTP 429, includes Retry-After and retryAfterSeconds.
  • ADMIN_RATE_LIMIT_EXCEEDED -> HTTP 429, includes Retry-After and retryAfterSeconds.
  • SLICE_QUEUE_FULL -> HTTP 503.
  • SLICE_QUEUE_CLIENT_LIMIT -> HTTP 429.
  • SLICE_QUEUE_TIMEOUT -> HTTP 503.
  • FILE_PROCESSING_TIMEOUT -> HTTP 422.

💰 Pricing API

GET /pricing

Returns full pricing object.

POST /pricing/FDM / POST /pricing/SLA (admin)

Create new material for selected technology.

{
  "material": "ASA",
  "price": 1200
}

PATCH /pricing/:technology/:material (admin)

Update existing material price only.

{
  "price": 950
}

DELETE /pricing/:technology/:material (admin)

Delete existing material from selected technology.


🛠️ Admin Endpoint

GET /admin/output-files (admin)

Lists generated .gcode / .sl1 files from output/.

{
  "success": true,
  "total": 2,
  "files": [
    {
      "fileName": "model-output-1741285245000.gcode",
      "downloadUrl": "/admin/download/model-output-1741285245000.gcode",
      "sizeBytes": 182734,
      "createdAt": "2026-03-05T10:07:25.000Z",
      "modifiedAt": "2026-03-05T10:07:27.000Z"
    },
    {
      "fileName": "model-output-1741285301000.sl1",
      "downloadUrl": "/admin/download/model-output-1741285301000.sl1",
      "sizeBytes": 941282,
      "createdAt": "2026-03-05T10:08:21.000Z",
      "modifiedAt": "2026-03-05T10:08:24.000Z"
    }
  ]
}

Generated artifacts are stored with the following convention for clarity and traceability:

  • InputName-output-<timestamp>.gcode
  • InputName-output-<timestamp>.sl1

GET /admin/download/:fileName (admin)

Downloads a generated .gcode / .sl1 artifact by file name.

Special token support:

  • ALL -> returns an application/zip stream that contains every currently valid output artifact.

Bulk ALL downloads are validated before streaming and return HTTP 413 with BULK_DOWNLOAD_LIMIT_EXCEEDED if the current output set exceeds MAX_ZIP_ENTRIES or MAX_ZIP_UNCOMPRESSED_BYTES.

Examples:

curl -L -H "x-api-key: <ADMIN_API_KEY>" \
  http://localhost:3000/admin/download/Cover-output-1777587775846.sl1 \
  -o Cover-output-1777587775846.sl1
curl -L -H "x-api-key: <ADMIN_API_KEY>" \
  http://localhost:3000/admin/download/ALL \
  -o output-files.zip

Common slicing error responses:

  • INVALID_SOURCE_ARCHIVE → uploaded ZIP is invalid or does not contain a supported file.
  • INVALID_SOURCE_GEOMETRY → uploaded source geometry is invalid/non-printable and auto-repair is disabled.
  • FILE_PROCESSING_TIMEOUT (HTTP 422) → processing exceeded 10 minutes for the uploaded file.

⚙️ Learn how to set up the .env, configs, input/output

1. Create your env file from template

cp .env.example .env

2. Create your pricing configuration file from the template

cp configs/pricing.example.json configs/pricing.json

Default pricing.example.json structure:

{
  "FDM": {
    "PLA": 1000,
    "ABS": 1000,
    "PETG": 1100,
    "TPU": 1100
  },
  "SLA": {
    "Standard": 2000,
    "ABS-Like": 2000,
    "Flexible": 2800
  }
}

3. Set at least ADMIN_API_KEY in .env

4. Start the app

  • local: npm start
  • docker: docker compose up -d --build

5. Runtime environment loading

The app reads .env automatically on local startup via dotenv, and Docker reads it via env_file.

Runtime folders used by the program

  • input/ → temporary working input directory used during conversion/slicing pipeline.
  • output/ → generated output artifacts (.gcode, .sl1, etc.).
  • configs/ → slicer profiles (prusa/*.ini, orca/*.json) + persistent pricing.json.

Runtime paths are root-scoped in both local and Docker execution. No app-local runtime folders are used (app/input, app/output, app/configs are intentionally not used).

Config files you can use out-of-the-box

  • Prusa process/printer profiles (.ini):
    • configs/prusa/FDM_0.1mm.ini
    • configs/prusa/FDM_0.2mm.ini
    • configs/prusa/FDM_0.3mm.ini
    • configs/prusa/SLA_0.025mm.ini
    • configs/prusa/SLA_0.05mm.ini
  • Orca machine/process profiles (.json):
    • configs/orca/Bambu_P1S_0.4_nozzle.json
    • configs/orca/FDM_0.1mm.json
    • configs/orca/FDM_0.2mm.json
    • configs/orca/FDM_0.3mm.json

You can add your own profiles (for example 2 FDM + 2 SLA for Prusa, or multiple Orca machine profiles), then select them per request with printerProfile (and processProfile for Orca).

Different printer/process profiles produce different G-code behavior in practice (speed, accelerations, cooling, supports, extrusion strategy), even for the same model.


⚙️ Configuration & Limits

You can customize pricing, security, and slicing behavior without changing endpoint contracts.

  • Pricing Matrix: Persisted in configs/pricing.json (managed via /pricing endpoints).
  • Admin Security: ADMIN_API_KEY environment variable controls access to pricing updates/deletes.
  • Admin Browser CORS Control: /admin/* browser-origin requests are constrained by ADMIN_CORS_ALLOWED_ORIGINS.
  • Admin File Listing: GET /admin/output-files requires ADMIN_API_KEY and returns generated output artifacts.
  • Admin File Download: GET /admin/download/:fileName requires ADMIN_API_KEY, allows downloading a single .gcode / .sl1 artifact, and supports ALL for ZIP download of all valid output files within configured ZIP limits.
  • Fail-Fast Security: Server startup is blocked if ADMIN_API_KEY is missing.
  • Security Logging: Admin auth failures log client IP with forwarded-header-aware parsing (requires TRUST_PROXY=true behind proxy).
  • Timing-Safe Auth: Admin API key comparison uses constant-time comparison to prevent timing side-channel attacks.
  • Upload Validation: Multer accepts only a single file on the choosenFile field with file extension validation at upload time.
  • Request Rate Limit: Slicing endpoints are IP-rate-limited (default 3 requests / 60s). Expired rate-limit buckets are automatically pruned.
  • Admin Rate Limit: Admin endpoints are IP-rate-limited (default 30 requests / 60s) to reduce brute-force API-key attempts.
  • Proxy Trust: Set TRUST_PROXY=true only behind a reverse proxy and configure TRUST_PROXY_CIDRS to trusted proxy CIDRs/names; forwarded headers are ignored otherwise.
  • Slicing Queue: CPU-heavy slice jobs are queued in arrival order and processed FIFO (MAX_CONCURRENT_SLICES, default 1).
  • Queue Fairness: Per-client queue ownership is bounded (MAX_SLICE_QUEUE_PER_IP) so one client cannot monopolize all pending capacity.
  • Queue Safety Limits: Queue length and wait timeout are bounded (MAX_SLICE_QUEUE_LENGTH, MAX_SLICE_QUEUE_WAIT_MS).
  • Upload Body Limit: Multipart upload size is capped (MAX_UPLOAD_BYTES, default 500MB).
  • ZIP Safety Limits: ZIP upload inspection and admin ALL bulk export are guarded by max entries (MAX_ZIP_ENTRIES, default 500) and max cumulative size (MAX_ZIP_UNCOMPRESSED_BYTES, default 500MB).
  • ZIP Content Rule: ZIP uploads must contain exactly one supported source file; unsupported or suspicious ZIP contents are rejected and cleaned up.
  • Body Parser Limits: JSON/form payload size is capped (JSON_BODY_LIMIT, FORM_BODY_LIMIT, default 1mb).
  • Slicer Profiles: Stored in configs/prusa/*.ini and configs/orca/*.json.
  • Timeouts: Internal 10-minute kill-switches prevent infinite loops during complex conversion/slicing operations and return FILE_PROCESSING_TIMEOUT when exceeded.
  • Model Fidelity Policy: Uploaded model data is never auto-healed or shape-corrected; invalid/non-printable source data is rejected with a clear error.
  • Supply-Chain Integrity: Docker build pins and verifies SHA256 checksums for downloaded PrusaSlicer and OrcaSlicer AppImages.
  • Python Resolver Security: PYTHON_EXECUTABLE must be absolute and existing when set; fallback resolution uses VIRTUAL_ENV and known absolute runtime paths.
  • Command Debugging: DEBUG_COMMAND_LOGS=true enables verbose converter/slicer stdout/stderr logging.

📝 Security & Runtime Change Snapshot (2026-04-21)

This repository currently includes the following synchronized changes across implementation and docs:

  • Admin security hardening: mandatory startup guard for ADMIN_API_KEY, timing-safe API key verification, and request-id-aware unauthorized logging.
  • Rate-limit controls: dedicated admin limiter (ADMIN_RATE_LIMIT_EXCEEDED), public slicing limiter (RATE_LIMIT_EXCEEDED), and Retry-After-aware 429 responses.
  • Proxy trust controls: forwarded header trust only when TRUST_PROXY=true and TRUST_PROXY_CIDRS is configured, with shared normalized client IP resolution.
  • Queue fairness and resilience: FIFO queue with bounded concurrency, per-client queued+active cap (MAX_SLICE_QUEUE_PER_IP), queue wait timeout, and explicit queue error codes.
  • Admin output download hardening: extension allowlist (.gcode, .sl1), ALL ZIP bulk download support, path/symlink/realpath checks, and pre-stream bulk ZIP resource limits.
  • Python subprocess execution hardening: centralized Python executable resolution, absolute-path validation, startup fail-fast behavior, and secure converter/orientation/transform subprocess execution.
  • Docker supply-chain validation: build-time SHA256 verification for slicer AppImages.
  • Documentation synchronization: global Claude guides (CLAUDE.md, .claude/CLAUDE.md) and folder-local guides under app/, configs/, and tests/testing-scripts/.

🧪 Test publication policy

  • tests/testing-scripts/ is intended to be public and versioned.
  • tests/testing-files/ sample payloads are intentionally excluded from repository publication.
  • tests/testing-scripts/results/ generated reports are runtime artifacts and are ignored.

📦 Release Log

Detailed version history is maintained in CHANGELOG.md.


📄 License

Copyright (c) Hajdú Patrik Zsolt. All rights reserved.

Proprietary, commissioned work published for demonstration and portfolio purposes only. No rights to use, copy, modify or distribute it are granted. See LICENSE.md for the full terms.