Skip to content

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

  • Directory@granit/data-exchange/ Import/export types and API functions (framework-agnostic)
    • @granit/react-data-exchange Import/export providers, lifecycle hooks, preset management
PackageRoleDepends on
@granit/data-exchangeDTOs, import/export API functionsaxios, @granit/utils
@granit/react-data-exchangeExportProvider, 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>
);
}
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;
}
FunctionEndpointDescription
fetchExportDefinitions(client, basePath)GET /definitionsList registered export definitions
fetchExportFields(client, basePath, name)GET /definitions/{name}/fieldsAvailable fields for a definition
createExportJob(client, basePath, request)POST /jobsCreate an export job
fetchExportJobStatus(client, basePath, jobId)GET /jobs/{jobId}Poll job status
downloadExportFile(client, basePath, jobId)GET /jobs/{jobId}/downloadDownload generated file
fetchExportPresets(client, basePath, name)GET /presets/{name}Saved presets for a definition
saveExportPreset(client, basePath, request)POST /presetsSave/update a preset
deleteExportPreset(client, basePath, name, preset)DELETE /presets/{name}/{preset}Delete a preset
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;
}
FunctionEndpointDescription
uploadImportFile(client, basePath, file, definitionName)POST /Upload file (multipart)
previewImport(client, basePath, jobId)POST /{jobId}/previewExtract headers, sample rows, mapping suggestions
confirmMappings(client, basePath, jobId, request)PUT /{jobId}/mappingsLock in column mappings
executeImport(client, basePath, jobId)POST /{jobId}/executeStart async execution
dryRunImport(client, basePath, jobId)POST /{jobId}/dry-runValidate 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}/reportFull execution report
downloadCorrectionFile(client, basePath, jobId)GET /{jobId}/correction-fileDownload error rows file

Fetches all registered export definitions. Cached 5 minutes.

Fetches available fields for a definition. Enabled when definitionName is defined.

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;
}

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>;
}

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;
}

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;
}

Fetches the execution report and provides correction file download.

interface UseImportReportReturn {
readonly report: UseQueryResult<ImportReportResponse>;
readonly downloadCorrection: () => Promise<void>;
}
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
LevelSourceDescription
ExactAutoExact column name match
FuzzyAutoEdit-distance matching
SemanticAutoAI-powered semantic matching
SavedPresetFrom a saved mapping preset
ManualUserUser-edited mapping
CategoryKey exportsPackage
Export typesExportJobResponse, CreateExportJobRequest, ExportFieldDescriptor, ExportDefinitionResponse@granit/data-exchange
Export APIcreateExportJob(), fetchExportJobStatus(), downloadExportFile()@granit/data-exchange
Export presetsExportPresetResponse, saveExportPreset(), deleteExportPreset()@granit/data-exchange
Import typesImportJobResponse, ImportPreviewResponse, ImportReportResponse, ImportColumnMapping@granit/data-exchange
Import APIuploadImportFile(), previewImport(), confirmMappings(), executeImport(), dryRunImport()@granit/data-exchange
Export hooksuseExportJob(), useExportDefinitions(), useExportFields(), useExportPresets()@granit/react-data-exchange
Import hooksuseImportJob(), useImportPreview(), useImportReport()@granit/react-data-exchange
ProvidersExportProvider, ImportProvider@granit/react-data-exchange
  • Granit.DataExchange module — .NET import/export pipeline (Extract → Map → Validate → Execute)
  • Querying — Export jobs apply the same filter/sort/preset parameters