hajdu-patrik/3D-Printer-Slicer-API
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.
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.
ProductivityREADME.md
Original3D Printer Slicer API (FDM & SLA)
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 /healthGET /pricingPOST /prusa/slicePOST /orca/sliceGET /openapi.jsonGET /docsGET /
Admin-protected
GET /health/detailedPOST /pricing/FDMPOST /pricing/SLAPATCH /pricing/:technology/:materialDELETE /pricing/:technology/:materialGET /admin/output-filesGET /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_ENVfallbacks).
Middleware
app/middleware/rateLimit.js- in-memory IP throttling for slice and admin routes (Retry-Afteraware 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/slicewith 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 andALLZIP bulk limit checks.app/services/slice.service.js- end-to-end slicing orchestrator and queue error mapping.app/services/slice/command.js- subprocess execution viaexecFilewith 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/docsand/openapi.json.
🧠 Slicing API Behavior
Both slicing endpoints accept multipart/form-data with required file field:
choosenFile
Optional fields:
layerHeightmaterialinfill(0-100)sizeUnit(mmorinch)keepProportions(true/false, defaulttrue)targetSizeX,targetSizeY,targetSizeZ(target dimensions in selected unit)scalePercent(uniform scale; cannot be combined withtargetSizeX/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→SLA0.1,0.2,0.3→FDM
- Rejects invalid
layerHeightvalues outside0.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/maxbuild volume) - You can override profile file with
printerProfilefromconfigs/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
FDMprocessing - 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
.envviaORCA_MACHINE_PROFILE(default:Bambu_P1S_0.4_nozzle.json)
- Machine profile file is resolved from
- Process profile file is selected by
layerHeight(0.1/0.2/0.3) and can be overridden via.env:ORCA_PROCESS_PROFILE_0_1ORCA_PROCESS_PROFILE_0_2ORCA_PROCESS_PROFILE_0_3
- Request-level profile overrides are supported:
printerProfile→ machine profile fromconfigs/orcaprocessProfile→ process profile fromconfigs/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_HEIGHTINVALID_LAYER_HEIGHT_FOR_ENGINEINVALID_LAYER_HEIGHT_FOR_TECHNOLOGYINVALID_MATERIAL_FOR_TECHNOLOGYMATERIAL_TECHNOLOGY_MISMATCHRATE_LIMIT_EXCEEDEDADMIN_RATE_LIMIT_EXCEEDEDINVALID_SOURCE_ARCHIVEINVALID_SOURCE_GEOMETRYUNSUPPORTED_FILE_FORMATORCA_PROFILE_INCOMPATIBLEINVALID_SIZE_UNITINVALID_KEEP_PROPORTIONSINVALID_SIZE_OPTIONSINVALID_ROTATION_OPTIONSCONFLICTING_SIZE_OPTIONSINVALID_PROFILE_NAMEPROFILE_NOT_FOUNDMODEL_DIMENSIONS_UNAVAILABLEMODEL_OUT_OF_PRINTER_BOUNDSFILE_PROCESSING_TIMEOUTSLICE_QUEUE_FULLSLICE_QUEUE_CLIENT_LIMITSLICE_QUEUE_TIMEOUTQUEUE_INTERNAL_ERRORINTERNAL_PROCESSING_ERROR
Queue and rate-limit response semantics
RATE_LIMIT_EXCEEDED-> HTTP429, includesRetry-AfterandretryAfterSeconds.ADMIN_RATE_LIMIT_EXCEEDED-> HTTP429, includesRetry-AfterandretryAfterSeconds.SLICE_QUEUE_FULL-> HTTP503.SLICE_QUEUE_CLIENT_LIMIT-> HTTP429.SLICE_QUEUE_TIMEOUT-> HTTP503.FILE_PROCESSING_TIMEOUT-> HTTP422.
💰 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>.gcodeInputName-output-<timestamp>.sl1
GET /admin/download/:fileName (admin)
Downloads a generated .gcode / .sl1 artifact by file name.
Special token support:
ALL-> returns anapplication/zipstream 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(HTTP422) → 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) + persistentpricing.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.iniconfigs/prusa/FDM_0.2mm.iniconfigs/prusa/FDM_0.3mm.iniconfigs/prusa/SLA_0.025mm.iniconfigs/prusa/SLA_0.05mm.ini
- Orca machine/process profiles (
.json):configs/orca/Bambu_P1S_0.4_nozzle.jsonconfigs/orca/FDM_0.1mm.jsonconfigs/orca/FDM_0.2mm.jsonconfigs/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/pricingendpoints). - Admin Security:
ADMIN_API_KEYenvironment variable controls access to pricing updates/deletes. - Admin Browser CORS Control:
/admin/*browser-origin requests are constrained byADMIN_CORS_ALLOWED_ORIGINS. - Admin File Listing:
GET /admin/output-filesrequiresADMIN_API_KEYand returns generated output artifacts. - Admin File Download:
GET /admin/download/:fileNamerequiresADMIN_API_KEY, allows downloading a single.gcode/.sl1artifact, and supportsALLfor ZIP download of all valid output files within configured ZIP limits. - Fail-Fast Security: Server startup is blocked if
ADMIN_API_KEYis missing. - Security Logging: Admin auth failures log client IP with forwarded-header-aware parsing (requires
TRUST_PROXY=truebehind 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
choosenFilefield with file extension validation at upload time. - Request Rate Limit: Slicing endpoints are IP-rate-limited (default
3requests /60s). Expired rate-limit buckets are automatically pruned. - Admin Rate Limit: Admin endpoints are IP-rate-limited (default
30requests /60s) to reduce brute-force API-key attempts. - Proxy Trust: Set
TRUST_PROXY=trueonly behind a reverse proxy and configureTRUST_PROXY_CIDRSto 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, default1). - 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, default500MB). - ZIP Safety Limits: ZIP upload inspection and admin
ALLbulk export are guarded by max entries (MAX_ZIP_ENTRIES, default500) and max cumulative size (MAX_ZIP_UNCOMPRESSED_BYTES, default500MB). - 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, default1mb). - Slicer Profiles: Stored in
configs/prusa/*.iniandconfigs/orca/*.json. - Timeouts: Internal 10-minute kill-switches prevent infinite loops during complex conversion/slicing operations and return
FILE_PROCESSING_TIMEOUTwhen 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_EXECUTABLEmust be absolute and existing when set; fallback resolution usesVIRTUAL_ENVand known absolute runtime paths. - Command Debugging:
DEBUG_COMMAND_LOGS=trueenables 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=trueandTRUST_PROXY_CIDRSis 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),ALLZIP 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 underapp/,configs/, andtests/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.