Data Exchange
@granit/data-exchange provides framework-agnostic types and API functions for the
import/export pipelines — mirroring Granit.DataExchange on the .NET backend.
@granit/react-data-exchange wraps these into React providers and hooks that manage
the full lifecycle: file upload → preview → column mapping → dry-run → execute → report.
For exports: definition discovery → field selection → job creation → status polling → auto-download.
Peer dependencies: axios, @granit/utils, react ^19, @tanstack/react-query ^5
Package structure
Section titled “Package structure”Directory@granit/data-exchange/ Import/export types and API functions (framework-agnostic)
- @granit/react-data-exchange Import/export providers, lifecycle hooks, preset management
| Package | Role | Depends on |
|---|---|---|
@granit/data-exchange | DTOs, import/export API functions | axios, @granit/utils |
@granit/react-data-exchange | ExportProvider, ImportProvider, lifecycle hooks | @granit/data-exchange, @tanstack/react-query, react |
import { ExportProvider, ImportProvider } from '@granit/react-data-exchange';import { api } from './api-client';
function DataManagement({ children }) { return ( <ExportProvider config={{ client: api, basePath: '/api/v1/exports' }}> <ImportProvider config={{ client: api, basePath: '/api/v1/imports' }}> {children} </ImportProvider> </ExportProvider> );}import { createExportJob, uploadImportFile } from '@granit/data-exchange';import type { ExportJobResponse, ImportJobResponse } from '@granit/data-exchange';TypeScript SDK — Export
Section titled “TypeScript SDK — Export”type ExportJobStatus = 'Queued' | 'Exporting' | 'Completed' | 'Failed';
interface ExportJobResponse { readonly id: string; readonly definitionName: string; readonly format: string; readonly status: ExportJobStatus; readonly rowCount: number | null; readonly fileName: string | null; readonly errorMessage: string | null; readonly createdAt: string; readonly completedAt: string | null;}
interface CreateExportJobRequest { readonly definitionName: string; readonly format: string; readonly selectedFields: readonly string[] | null; readonly includeIdForImport: boolean; readonly sort: string | null; readonly filter: Readonly<Record<string, string>> | null; readonly presets: Readonly<Record<string, string>> | null; readonly search: string | null;}
interface ExportFieldDescriptor { readonly propertyPath: string; readonly clrTypeName: string; readonly header: string | null; readonly format: string | null; readonly order: number; readonly isNavigation: boolean;}
interface ExportDefinitionResponse { readonly name: string; readonly entityType: string; readonly supportedFormats: readonly string[];}
interface ExportPresetResponse { readonly definitionName: string; readonly presetName: string; readonly selectedFields: readonly string[]; readonly format: string; readonly includeIdForImport: boolean;}API functions
Section titled “API functions”| Function | Endpoint | Description |
|---|---|---|
fetchExportDefinitions(client, basePath) | GET /definitions | List registered export definitions |
fetchExportFields(client, basePath, name) | GET /definitions/{name}/fields | Available fields for a definition |
createExportJob(client, basePath, request) | POST /jobs | Create an export job |
fetchExportJobStatus(client, basePath, jobId) | GET /jobs/{jobId} | Poll job status |
downloadExportFile(client, basePath, jobId) | GET /jobs/{jobId}/download | Download generated file |
fetchExportPresets(client, basePath, name) | GET /presets/{name} | Saved presets for a definition |
saveExportPreset(client, basePath, request) | POST /presets | Save/update a preset |
deleteExportPreset(client, basePath, name, preset) | DELETE /presets/{name}/{preset} | Delete a preset |
TypeScript SDK — Import
Section titled “TypeScript SDK — Import”type ImportJobStatus = | 'Created' | 'Previewed' | 'Mapped' | 'Executing' | 'Completed' | 'PartiallyCompleted' | 'Failed' | 'Cancelled';
interface ImportJobResponse { readonly id: string; readonly definitionName: string; readonly originalFileName: string; readonly mimeType: string; readonly fileSizeBytes: number; readonly status: ImportJobStatus; readonly createdAt: string; readonly completedAt: string | null;}
type MappingConfidence = 'Manual' | 'Saved' | 'Exact' | 'Fuzzy' | 'Semantic';
interface ImportColumnMapping { readonly sourceColumn: string; readonly targetProperty: string | null; readonly confidence: MappingConfidence;}
interface ImportFieldMetadata { readonly propertyPath: string; readonly clrTypeName: string; readonly displayName: string; readonly description: string | null; readonly isRequired: boolean;}
interface ImportPreviewResponse { readonly headers: readonly string[]; readonly previewRows: readonly (readonly string[])[]; readonly suggestions: readonly ImportColumnMapping[]; readonly fieldMetadata: readonly ImportFieldMetadata[];}
interface ImportReportResponse { readonly importJobId: string; readonly finalStatus: ImportJobStatus; readonly totalRows: number; readonly succeededRows: number; readonly failedRows: number; readonly skippedRows: number; readonly insertedRows: number; readonly updatedRows: number; readonly duration: string; readonly rowErrors: readonly ImportRowError[];}
type ImportRowErrorKind = 'Conversion' | 'Validation' | 'Persistence' | 'Identity';
interface ImportRowError { readonly rowNumber: number; readonly kind: ImportRowErrorKind; readonly errorCodes: readonly string[]; readonly message: string;}API functions
Section titled “API functions”| Function | Endpoint | Description |
|---|---|---|
uploadImportFile(client, basePath, file, definitionName) | POST / | Upload file (multipart) |
previewImport(client, basePath, jobId) | POST /{jobId}/preview | Extract headers, sample rows, mapping suggestions |
confirmMappings(client, basePath, jobId, request) | PUT /{jobId}/mappings | Lock in column mappings |
executeImport(client, basePath, jobId) | POST /{jobId}/execute | Start async execution |
dryRunImport(client, basePath, jobId) | POST /{jobId}/dry-run | Validate without persisting |
fetchImportJob(client, basePath, jobId) | GET /{jobId} | Poll job status |
cancelImportJob(client, basePath, jobId) | DELETE /{jobId} | Cancel a job |
fetchImportReport(client, basePath, jobId) | GET /{jobId}/report | Full execution report |
downloadCorrectionFile(client, basePath, jobId) | GET /{jobId}/correction-file | Download error rows file |
React bindings
Section titled “React bindings”Export hooks
Section titled “Export hooks”useExportDefinitions()
Section titled “useExportDefinitions()”Fetches all registered export definitions. Cached 5 minutes.
useExportFields(definitionName)
Section titled “useExportFields(definitionName)”Fetches available fields for a definition. Enabled when definitionName is defined.
useExportJob()
Section titled “useExportJob()”Full export lifecycle: create job → poll status (2s) → auto-download on completion.
interface UseExportJobReturn { readonly startExport: (request: CreateExportJobRequest) => void; readonly job: ExportJobResponse | null; readonly isExporting: boolean; readonly isCreating: boolean; readonly error: Error | null; readonly reset: () => void;}useExportPresets(definitionName)
Section titled “useExportPresets(definitionName)”CRUD for export presets per definition.
interface UseExportPresetsReturn { readonly presets: UseQueryResult<readonly ExportPresetResponse[]>; readonly save: UseMutationResult<void, Error, SaveExportPresetRequest>; readonly remove: UseMutationResult<void, Error, string>;}Import hooks
Section titled “Import hooks”useImportJob()
Section titled “useImportJob()”Full import lifecycle: upload → preview → confirm mappings → execute → poll until terminal.
interface UseImportJobReturn { readonly upload: (file: File, definitionName: string) => void; readonly confirmMap: (request: ConfirmMappingsRequest) => void; readonly execute: () => void; readonly cancel: () => void; readonly job: ImportJobResponse | null; readonly isTerminal: boolean; readonly isUploading: boolean; readonly isConfirming: boolean; readonly isExecuting: boolean; readonly isPolling: boolean; readonly error: Error | null; readonly reset: () => void;}useImportPreview()
Section titled “useImportPreview()”Preview management: extract headers, edit mappings, dry-run validation.
interface UseImportPreviewReturn { readonly preview: (jobId: string) => void; readonly headers: readonly string[]; readonly previewRows: readonly (readonly string[])[]; readonly suggestions: readonly ImportColumnMapping[]; readonly fieldMetadata: readonly ImportFieldMetadata[]; readonly mappings: ImportColumnMapping[]; readonly updateMapping: (sourceColumn: string, targetProperty: string | null) => void; readonly dryRun: (jobId: string) => void; readonly dryRunReport: ImportReportResponse | null; readonly isPreviewing: boolean; readonly isDryRunning: boolean; readonly error: Error | null; readonly reset: () => void;}useImportReport(jobId)
Section titled “useImportReport(jobId)”Fetches the execution report and provides correction file download.
interface UseImportReportReturn { readonly report: UseQueryResult<ImportReportResponse>; readonly downloadCorrection: () => Promise<void>;}Import lifecycle
Section titled “Import lifecycle”graph LR
Upload["Upload file"] --> Preview["Preview & map"]
Preview --> DryRun["Dry-run"]
DryRun --> Execute["Execute"]
Execute --> Poll["Poll status"]
Poll --> Report["Report"]
Report --> Correction["Correction file"]
DryRun -.->|fix mappings| Preview
Mapping confidence
Section titled “Mapping confidence”| Level | Source | Description |
|---|---|---|
Exact | Auto | Exact column name match |
Fuzzy | Auto | Edit-distance matching |
Semantic | Auto | AI-powered semantic matching |
Saved | Preset | From a saved mapping preset |
Manual | User | User-edited mapping |
Public API summary
Section titled “Public API summary”| Category | Key exports | Package |
|---|---|---|
| Export types | ExportJobResponse, CreateExportJobRequest, ExportFieldDescriptor, ExportDefinitionResponse | @granit/data-exchange |
| Export API | createExportJob(), fetchExportJobStatus(), downloadExportFile() | @granit/data-exchange |
| Export presets | ExportPresetResponse, saveExportPreset(), deleteExportPreset() | @granit/data-exchange |
| Import types | ImportJobResponse, ImportPreviewResponse, ImportReportResponse, ImportColumnMapping | @granit/data-exchange |
| Import API | uploadImportFile(), previewImport(), confirmMappings(), executeImport(), dryRunImport() | @granit/data-exchange |
| Export hooks | useExportJob(), useExportDefinitions(), useExportFields(), useExportPresets() | @granit/react-data-exchange |
| Import hooks | useImportJob(), useImportPreview(), useImportReport() | @granit/react-data-exchange |
| Providers | ExportProvider, ImportProvider | @granit/react-data-exchange |
See also
Section titled “See also”- Granit.DataExchange module — .NET import/export pipeline (Extract → Map → Validate → Execute)
- Querying — Export jobs apply the same filter/sort/preset parameters