How to use the Export API
General process
The diagram below provides a visual overview of the process for using the Export API.
- The client begins by sending a POST request to the server. This request includes a JSON file containing the configuration settings for the desired exports and initiates the export process on the server.
- In response to the POST request, the Export API returns an order state (described in more detail below). The returned name (ID) is required for subsequent requests.
- If the POST request is successful, the client periodically sends GET requests to the API to check the progress of the export. The name received in step 2 is used as a part of the address for these requests.
- Once the done flag is set to true and the state in the metadata is STATE_SUCCEEDED, the client can proceed to download the export. A final GET request is sent to retrieve the generated export files, which are provided in a compressed ZIP archive. If the export process fails and the state is STATE_FAILED, no download will be available. In this case, the response will include an appropriate error message.
Response type OrderState
The response from the API includes the following information:
- name: A unique ID under which the export order is managed internally.
-
metadata: Contains the current state of the export process, among other information. Possible values are:
- STATE_UNSPECIFIED: Default state, typically returned for invalid GetOparation calls
- STATE_PENDING: The export order is queued and waiting for a resources.
- STATE_RUNNING: The export process is currently in progress.
- STATE_SUCCEEDED: The export has been completed successfully.
- STATE_FAILED: The export process has failed.
-
done: A flag indicating whether the export process has finished.
- If the state is STATE_FAILED, detailed error information will also be included in the response.
For additional technical details, refer to the Swagger UI.
Authorization
To request an export using the Export API, you must first athenticate on the octoplant server using your username and password.
In addition, you will need the following credentials:
- Client ID: public-api
- Client secret: ff99971a-f8c3-4d21-5345-f7cb021b4b54
Successful authentication returns a token, which must be included in all subsequent API requests.
Example for the Export API integration
Below is the example of the Export API integration:
const clientId = "public-api";
const clientSecret = "ff99971a-f8c3-4d21-5345-f7cb021b4b54";
const username = "versiondog"; // octoplant user username
const password = "change-it"; // octoplant user password
const baseUrl = "https://localhost:64023"; // octoplant server address and port of the api
function grpcStatusCodeToText(code) {
switch (code) {
case 0: return "OK";
case 1: return "CANCELLED";
case 2: return "UNKNOWN";
case 3: return "INVALID_ARGUMENT";
case 4: return "DEADLINE_EXCEEDED";
case 5: return "NOT_FOUND";
case 6: return "ALREADY_EXISTS";
case 7: return "PERMISSION_DENIED";
case 8: return "RESOURCE_EXHAUSTED";
case 9: return "FAILED_PRECONDITION";
case 10: return "ABORTED";
case 11: return "OUT_OF_RANGE";
case 12: return "UNIMPLEMENTED";
case 13: return "INTERNAL";
case 14: return "UNAVAILABLE";
case 15: return "DATA_LOSS";
case 16: return "UNAUTHENTICATED";
default: return `Unknown code ${code}`;
}
}
async function handleErrorResponse(response) {
if (response.ok)
return
let error = await response.json();
if (error.code)
error["codeText"] = grpcStatusCodeToText(error.code);
if (error.error.code)
error.error["codeText"] = grpcStatusCodeToText(error.error.code);
console.dir(error);
throw new Error(`Response status: ${response.status}`);
}
// send the post / get request message
async function fetchGrpc(input, init) {
if (init.body)
console.log(`${init.method}: ${input} with body: ${init.body}`);
else
console.log(`${init.method}: ${input}`);
const response = await fetch(input, init);
await handleErrorResponse(response);
return response;
}
// authentication returns a token for the requests
async function authenticate() {
const response = await fetchGrpc(`${baseUrl}/v1/oauth2/token`, {
"credentials": "include",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
},
"body": `grant_type=password&username=${username}&password=${password}&client_id=${clientId}&client_secret=${clientSecret}`,
"method": "POST",
"mode": "cors"
});
const authData = await response.json()
return authData.access_token
}
// request the export order
async function startExport(token, data) {
const response = await fetchGrpc(`${baseUrl}/v1/order`, {
"credentials": "include",
"headers": {
"Accept": "application/json",
"authorization": `Bearer ${token}`
},
"body": JSON.stringify(data),
"method": "POST",
"mode": "cors"
});
return await response.json()
}
// request a cancel of the ordered export
async function cancelExport(token, name) {
const response = await fetchGrpc(`${baseUrl}/v1/order/${name}/cancel`, {
"credentials": "include",
"headers": {
"Accept": "application/json",
"authorization": `Bearer ${token}`
},
"method": "POST",
"mode": "cors"
});
return await response.json()
}
// request and perform the download of the ordered export
async function downloadExport(token, name) {
const response = await fetchGrpc(`${baseUrl}/v1/order/${name}/download`, {
"credentials": "include",
"headers": {
"Accept": "application/json",
"authorization": `Bearer ${token}`
},
"method": "GET",
"mode": "cors"
});
return await response.blob()
}
// request the status of the export
async function getExport(token, name) {
const response = await fetchGrpc(`${baseUrl}/v1/order/${name}`, {
"credentials": "include",
"headers": {
"Accept": "application/json",
"authorization": `Bearer ${token}`
},
"method": "GET",
"mode": "cors"
});
let j = await response.json()
if (j.error && j.error.code) {
j.error.codeText = grpcStatusCodeToText(j.error.code);
}
return j;
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// create a simple export
async function simpleExport(token) {
// request export with the json for the wished exports - here: project tree
let e = await startExport(token, {
exportContents: {
projectTree: {}
}
});
console.dir(e);
// request the status of the export
// if done is set to true: the creation is finished (succesful or failed)
do {
await sleep(1000);
e = await getExport(token, e.name);
// print the response (JSON) - just for documentation
console.dir(e);
} while (!e.done)
// download the ordered export.
// the zip package includes a contents.json and all requested exports
let d = await downloadExport(token, e.name)
// Just printing the blob - actually save the zip file
console.dir(d)
}
async function main() {
const token = await authenticate();
const fn = simpleExport;
try {
console.log(`Running function: ${fn.name}`);
await fn(token);
} catch (e) {
console.error(`Error in function ${fn.name}:`, e);
}
}