The Typefi 8 Server API (Application Programming Interface) provides integrators with a standards-based method of interacting with Typefi 8 from their own applications. The focus of the API is to allow for the running of workflows, getting and putting of assets, viewing and interacting with projects.
For additional insights, watch Ben Hauser’s 2016 Typefi User Conference presentation below:
Introduction
The Typefi 8 Server API is based on the REST (Representational State Transfer) web service architecture. All access is via HTTP and JSON is used for all data transfer. In short, a client application makes an HTTP request. If the response to that request is informational in nature, the returned data is delivered as JSON. If instead the request is for a particular resource, the resource itself is returned. The client application may be as simple as a web browser.
Authentication to all WSI servlets is handled with Basic Authentication (see RFC 2617).
All timestamps are returned in ISO 8601 format:
YYYY-MM-DDTHH:MM:SSZ
POST requests that furnish data to an API servlet should set the “Content-Type” HTTP header field for the request to “multipart/form-data” (see RFC 2616, section 14). All requests return standard HTTP response codes, such as 200
(OK) and 401
(Unauthorized).
Resources
- Basic Authentication (https://www.ietf.org/rfc/rfc2617.txt)
- HTTP Header Field Definitions (https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)
- HTTP Response Codes (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
- REST (https://en.wikipedia.org/wiki/Representational_state_transfer)
HTTP
Where possible, the API uses appropriate HTTP verbs for each action.
DELETE
. Used for deleting resources.GET
. Used for retrieving resources.HEAD
. Can be issued against any resource to get just the HTTP header info.PATCH
. Used for replacing partial resources.PUT
. Used for replacing resources or collections. For PUT requests with no body attribute, be sure to set the Content-Length header to zero.
The API makes use of the following HTTP response status codes within servlets.
200 OK
. All400 Bad Request
. Files, Projects, TSS, Workflows401 Unauthorized
. All403 Forbidden
. Files, Workflows, Jobs404 Not Found
. Files, Jobs, Projects, Templates, TSS, Workflows409 Conflict
. TSS500 Internal Server Error
. Files, Jobs, Workflows
Calls to servlets always results in one of the above status codes being returned. When the codes are returned as JSON objects, these contain the properties
- Code, the numeric HTTP response code, such as
401
. - Error, the description corresponding to the HTTP response code, such as “Unauthorized”. This is not included for success (
200
) codes. - URL of the API request, such as http://localhost:8080/tps/api/v1/authenticate
Examples
Success
{
"code": 200,
"url": "http://localhost:8080/tps/api/v1/files/delete/draft.docx"
}
Failure
{
"code": 401,
"error": "Unauthorized",
"url": "http://localhost:8080/tps/api/v1/authenticate"
}
Resources
The REST-assured domain specific language allows REST services to be tested using single lines of Java code, as demonstrated by the following examples.
// Get the results of a GET request for files as a string,
// using admin credentials
given()
.auth().preemptive().basic("admin", "admin")
.get("http://localhost:8090/tps/api/v1/files")
.asString();
// Send a PUT request to files, using Contents.txt as the
// multi-part data and the credentials of user jbloggs.
// Get the result as a string
given()
.auth().preemptive().basic("jbloggs", "abc123")
.multiPart(new File("/Users/jbloggs/Desktop/Contents.txt"))
.put("http://localhost:8090/tps/api/v1/files/Chapter1/")
.asString();
HTTPS
HTTP basic authentication means passwords are sent in the clear. If SSL is not used then this allows for easy eavesdropping and hijacking of authentication credentials. SSL is therefore strongly recommended for all Typefi versions.
- Cloud. HTTPS compulsory.
- Workgroup. HTTPS strongly recommended; optional by default.
- Desktop. HTTPS recommended; optional by default.
Every API call must authenticate.
In cloud mode a customer parameter should be added to all requests, set to the customer to which the user making the request belongs.
Versioning
The version is included in the URL rather than a header to maintain browser explorability of the resources across versions. So, for example, to list the files in a repository the URL may be similar to the following
https://{hostname}/api/v1/files
The API version is incremented when changes are made that have the potential to break existing code. Thus, the version is incremented when:
- New mandatory parameter(s) are introduced; or
- New data is added to JSON reponse(s).
The API version is not incremented when:
- New optional parameter(s) are introduced; or
- Refactoring is performed.
API version history
API Version | Minimum Typefi Server | |
---|---|---|
files | v1 | 8.0.0 |
v2 | 8.2.3 | |
v3 | 8.10 | |
tss | v1 | 8.0.0 |
v2 | 8.4.0 | |
v3 | 8.5.0 | |
workflows | v1 | 8.0.0 |
v2 | 8.2.0 | |
v3 | 8.5.0 | |
jobs | v1 | 8.0.0 |
properties | v1 | 8.0.0 |
projects | v1 | 8.0.0 |
MIME Structure
Many of the servlets require data to be sent as multipart MIME requests. This provides compatibility with HTML forms and makes it fairly straightforward to embed multiple types of data in a single request.
A sample multipart MIME request looks like this:
POST /put HTTP/1.1
Pragma: no-cache
Content-Type: multipart/form-data; boundary=XYTxYDxxYYYApEf
Host: 192.168.1.147:8080
Content-Length: 10268
Connection: Keep-Alive
--XYTxYDxxYYYApEf
Content-Disposition: form-data; name"File"; filename="=?ISO-8859-1?Q?/Test/Content/ParallelsTest1.doc?="
Content-Type: application/octet-stream
{\rtf1 …. File contents …. }
--XYTxYDxxYYYApEf--
The request contains the following information:
POST /put HTTP/1.1
POST is the HTTP method to use to transmit the data. HTTP/1.1 declares this as compatible with the HTTP 1.1 spec.
Pragma: no-cache
This indicates that the results of the request should not be cached. That is, every request will recalculate the results.
Content-Type: multipart/form-data; boundary=XYTxYDxxYYYApEf
The Content-Type: multipart/form-data indicates that what follows this header information is multipart MIME data. The boundary statement lists the unique text string that will be used to separate the multiple parts of the MIME body.
Host: 192.168.1.147:8080
This is the IP or host name of the server the client is talking to.
Content-Length: 10268
This is the total length in bytes of the message body. This includes the MIME boundary separators but does not include the HTTP header information.
Connection: Keep-Alive
This indicates that the client may reuse the authorization information for multiple requests.
--XYTxYDxxYYYApEf
The start of the message body. The start must include a CRLF and 2 dashes preceding the boundary string.
Content-Disposition: form-data; name"File"; filename="=?ISO-8859-1?Q?/Test/Content/ParallelsTest1.doc?="
Content-Type: application/octet-stream
Content-Disposition describes this MIME part. This should be set to form-data. The name of the part is servlet specific. In this example, the filename attribute has been Q-Encoded. The Content-Type field describes the data that follows. In this case it is the contents of a file.
{\rtf1 …. File contents …. }
--XYTxYDxxYYYApEf--
After Content-Disposition is another blank line (a CRLF) and then the MIME part data. After the file contents, another boundary string is written preceded by the double-dashes. A double-dash at the end of the boundary string indicates the end of the MIME content.
Here is a sample with 2 MIME parts:
POST /put HTTP/1.1
Pragma: no-cache
Content-Type: multipart/form-data; boundary=XYTxYDxxYYYApEf
Host: 192.168.1.147:8080
Content-Length: 10268
Connection: Keep-Alive
--XYTxYDxxYYYApEf
Content-Disposition: form-data; name"File"; filename="=?ISO-8859-1?Q?/Test/Content/ParallelsTest1.doc?="
Content-Type: application/octet-stream
{\rtf1 …. File contents …. }
--XYTxYDxxYYYApEf
Content-Disposition: form-data; name"File"; filename="=?ISO-8859-1?Q?/Test/Content/ParallelsTest2.doc?="
Content-Type: application/octet-stream
{\rtf1 …. File contents …. }
--XYTxYDxxYYYApEf—
You must set the Content-Disposition to ‘form-data’ (no quotes) and the filename parameter is required. It’s best to Q-encode your filename to avoid issues with non-ASCII characters.
See RFC 2047.
API Servlets
The remainder of this document details all currently available API servlets. Please report any problems or suggestions to support@typefi.com.
/api/v1/files
View and interact with files on the server.
Get
- If path maps to a folder then a list of the folder contents is returned, along with a
cms
attribute which is set to true if the file system used is content management and false otherwise. - If path maps to a file then the actual file is returned in its original (raw) form.
- If
checkout
is set to true then this works as above except that all files are checked out. If any items are reached that cannot be checked out, such as files that have already been checked out, then no further operations are undertaken and HTTP status code403 (Forbidden)
is returned. This means that some files may be checked out as a result. For example, if checkout is performed, in order, on files A, B and C and B is already checked out, A will be checked out, then a 403 will be returned. - If
cancelCheckout
is set to true then this works in the same way as checkout, except that checkout is cancelled for all affected files - To make a file read-only check it out
- Check out operations are only supported when a CMS is used
- If
extensions
contains a list of one or more comma separated values then only files that have an extension that is contained within this list are returned.
Syntax
/api/v1/files [path] [checkout=true|false] [cancelCheckout=true|false] [extensions=Extension1,Extension2,…,ExtensionN] [customer]
Example Requests
GET https://{hostname}/api/v1/files
GET https://{hostname}/api/v1/files/Typefi
GET https://{hostname}/api/v1/files/Typefi?extensions=docx
GET https://{hostname}/api/v1/files/Typefi?extensions=docx,pdf
GET https://{hostname}/api/v1/files/Typefi/User+Guide+Version+8/Installation+Guide.docx
GET https://{hostname}/api/v1/files/Typefi/User+Guide+Version+8/Installation+Guide.docx?checkout=true
GET https://{hostname}/api/v1/files/Typefi/User+Guide+Version+8/Installation+Guide.docx?cancelCheckout=true
Example Responses
File contents are returned as a MIME part named with the file name
Folder contents are returned as JSON
{
"files": [
{
"type": "folder",
"name": "2016-03-03 10.23.30",
"checkedOutBy": "",
"size": "",
"modified": "2016-03-03T00:23:52Z",
"path": "/Md/2016-03-03 10.23.30",
"isVersioningAvailable": true,
"isCheckedOut": false,
"id": "",
"isCheckedOutByOtherUser": false,
"versions": []
},
{
"type": "file",
"name": "API.md",
"checkedOutBy": "",
"size": "34999",
"modified": "2016-03-03T00:43:47Z",
"path": "/Md/API.md",
"isVersioningAvailable": true,
"isCheckedOut": false,
"id": "",
"isCheckedOutByOtherUser": false,
"versions": [
{
"size": 35172,
"modified": "2016-03-02T03:18:12Z",
"number": 1,
"user": "",
"comment": ""
},
{
"size": 35231,
"modified": "2016-03-02T04:31:34Z",
"number": 2,
"user": "Justin Debuse",
"comment": "Uploaded on 2016-Mar-02 14.31.32"
}
]
},
],
"filestoreType": "FOLDER"
}
Post
- Uploads the file contained in the multi-part form data in the folder specified by path.
- The multi-part form data must be RFC 1867 compliant. Note that the name parameter must be non-empty.
- The path must be a valid folder. Files can be uploaded to folders that do not already exist; the folder is created if necessary. Folders can be created via a request with no attached file.
- If
create
is set to true then file must not exist in the file system. - If
update
is set to true then file must exist in the file system. - If
checkedOut
is set to true then file is checked out. - No check in option is supported since this is unused when no CMS is used, not permitted when creating files and always used when updating files.
- If the filestore has versioning enabled then the uploaded file is added as a new version of the file if the file already exists, and an optional comment may be included using the
comment
parameter. To prevent this behaviour thedisableVersioning
parameter should be set to true.
Syntax
/api/v1/files
[path] [<Multi-part form data>] [create=true|false]
[update=true|false] [checkedOut=true|false] [comment]
[disableVersioning=true|false] [customer]
Example Requests
// Creates the file contained in the multi-part form data
// in the specified folder. The file must not already exist
// in the filesystem
POST https://{hostname}/api/v1/files/Typefi?create=true
// Updates a file. The file must exist in the filesystem
POST https://{hostname}/api/v1/files/Guide.docx?update=true
Patch
- If path maps to a folder then a 404 is returned.
- If path maps to a file and
checkedOut
is set to true then file is checked out, provided it is not already checked out. - If path maps to a file and
checkedOut
is set to false then checkout is cancelled for the file, provided it is checked out. - Systems that do not support Patch may instead use Put.
Syntax
/api/v1/files [path] [checkedOut=true|false] [customer]
Example Requests
PATCH https://{hostname}/api/v1/files/Guide.docx?checkedOut=true
Delete
- Deletes the file specified by path
- If the filestore has versioning enabled then the file is copied to the version history to permit subsequent undo; an optional comment may be included, using the
comment
parameter.
Syntax
/api/v1/files [path] [comment] [customer]
Example Requests
DELETE https://{hostname}/api/v1/files/Guide.docx
/api/v2/files
Get
- Added missing attribute "user".
- Added missing attribute "comment".
Syntax
/api/v2/files [path] [checkout=true|false] [cancelCheckout=true|false] [extensions=Extension1,Extension2,…,ExtensionN] [customer]
Example Request
GET https://{hostname}/api/v2/files/Typefi/User+Guide+Version+8
Example Responses
new user
and comment
tags in latest version of a file.
{
"type": "file",
"name": "API.md",
"checkedOutBy": "",
"size": "34999",
"modified": "2016-03-03T00:43:47Z",
"path": "/Md/API.md",
"isVersioningAvailable": true,
"isCheckedOut": false,
"id": "",
"isCheckedOutByOtherUser": false,
"user": "Admin",
"comment": "Checked in version 3 on 2018-Apr-12 10.39.48"
"versions": [
{
"size": 35172,
"modified": "2016-03-02T03:18:12Z",
"number": 1,
"user": "",
"comment": ""
}, ...
Post
Version 2 of the files servlet is identical to version 1 with the exception of the following changes:
- An optional
copyFrom
parameter is available for the POST servlet. This contains one or more comma separated paths of files which are to be copied to the folder specified by path - An optional
moveFrom
parameter is also available for the POST servlet. This works in the same way ascopyFrom
, except that files are moved rather than copied. - 8.6 An optional unzip parameter is available for the POST servlet. This controls whether or not a zip file should be automatically unzipped after upload.
Syntax
/api/v2/files
[path] [<Multi-part form data>] [create=true|false]
[update=true|false] [checkedOut=true|false] [unzip=true|false] [comment]
[disableVersioning=true|false]
[copyFrom=File1,File2,…,FileN]
[moveFrom=File1,File2,…,FileN]
[customer]
Example Requests
// Creates the file contained in the multi-part form data
// in the specified folder. The file must not already exist
// in the filesystem
POST https://{hostname}/api/v2/files/Typefi?create=true
// Updates a file. The file must exist in the filesystem
POST https://{hostname}/api/v2/files/Guide.docx?update=true
// Copies /Marketing/cover.indd and /Content/main.indd to the Typefi folder
POST https://{hostname}/api/v2/files/Typefi?copyFrom=/Marketing/cover.indd,/Content/main.indd
// Moves /Marketing/cover.indd and /Content/main.indd to the Archive folder
POST https://{hostname}/api/v2/files/Archive?moveFrom=/Marketing/cover.indd,/Content/main.indd
//Does not unzip files when uploading zip files.
POST https://{hostname}/api/v2/files?unzip=false
Patch
v2 patch request introduced a new parameter newFileName
to rename a file other than v1. This does not change the extension of the file.
Syntax
/api/v2/files [path] [newFileName] [customer]
Example Requests
PATCH https://{hostname}/api/v2/files/Guide.docx?newFileName=Guide456
Put
PATCH request with revertVersion
parameter is used to revert file which has the limitation of adding a comment. Put request allows to add a comment.
Syntax
/api/v2/files [path] [revertVersion] [comment]
Example Requests
PATCH https://{hostname}/api/v1/files/Guide.docx?revertVersion=8&comment=new comment
/api/v3/files
Get
Version 3 of the files servlet is identical to version 2, except that:
- v3 is used in place of v2 within the URL.
Syntax
/api/v3/files [path][checkout=true|false][canceCheckout=true|false]
[extensions=Extension1,Extension2,...,ExtensionN][customer]
Example request
GET https://{hostname}/api/v3/files/Typefi/User+Guide+Version+8
Example response
{
"type": "file",
"name": "API.md",
"checkedOutBy": "",
"size": "34999",
"modified": "2016-03-03T00:43:47Z",
"path": "/Md/API.md",
"isVersioningAvailable": true,
"isCheckedOut": false,
"id": "",
"isCheckedOutByOtherUser": false,
"user": "Admin",
"comment": "Checked in version 3 on 2018-Apr-12 10.39.48"
"versions": [
{
"size": 35172,
"modified": "2016-03-02T03:18:12Z",
"number": 1,
"user": "",
"comment": ""
}, ...
Post
Version 3 of the files servlet is identical to version 2, except that:
- 8.10 Added an optional
suppressVersionCreation=true|false
parameter to the POST request endpoint.
The suppressVersionCreation
parameter, when set to true
, prevents the creation of new document versions during saving. This is beneficial for client systems that frequently save documents, such as in an autosave feature, to avoid creating new versions with each autosave.
Syntax
/api/v3/files
[path][<Multi-part form data>][create=true|false]
[update=true|false][checkedOut=true|false][unzip=true|false][comment]
[disableVersioning=true|false]
[suppressVersionCreation=true|false]
[copyFrom=File1,File2,…,FileN]
[moveFrom=File1,File2,…,FileN]
[customer]
Example requests
// Prevents Typefi Server from creating a new version.
POST https://{hostname}/api/v3/files/Guide.docx?suppressVersionCreation=true
// Allows Typefi Server to create a new version.
POST https://{hostname}/api/v3/files/Guide.docx?suppressVersionCreation=false
Patch
- v3/files Patch request is identical to v2.
Syntax
/api/v3/files [path] [newFileName] [customer]
Example requests
PATCH https://{hostname}/api/v3/files/Guide.docx?newFileName=Guide456
Put
- v3/files Put request is identical to v2.
Syntax
/api/v3/files [path] [revertVersion] [comment]
Example requests
PUT https://{hostname}/api/v3/files/Guide.docx?revertVersion=8&comment=new comment
/api/v1/jobs
View and interact with jobs on the server.
Get
- If
path
is not specified then all jobs are returned. - If
limit
is specified then the number of jobs returned is limited to the specified value. For example, a limit of 10 will return the ten most recent jobs. - If
offset
is specified then the list of jobs returned is offset by the specified value. For example, an offset of 5 will return all except the five most recent jobs. - If path maps to a whole number then the job with the specified id is returned.
- If path maps to the path of a job then the job with the specified path is returned.
- When a single job is returned, the names of its outputs are also included.
- The returned job data includes a
jobStatus
, which takes one of the following values: "Unknown", "Started", "Completed", "Cancelled", "Deleted", "Failed". - When a job is first created, its status is set to "Started" and its start time is not set; it may potentially then spend time in a queue. Next, the job starts running, at which point its start time is set. Once the job has finished running its status is set to "Completed" if it ran successfully, "Cancelled" if it was cancelled and "Failed" if an error occurred.
Syntax
/api/v1/jobs [path] [limit] [offset] [customer]
Example Requests
GET https://{hostname}/api/v1/jobs
GET https://{hostname}/api/v1/jobs/18+Jan+2014+07_38_40
GET https://{hostname}/api/v1/jobs/38271673
Example Response
Job(s) as JSON
{
"id": 2147482517,
"startTime": "2015-04-27T00:12:15.414Z",
"endTime": "2015-04-27T00:12:32.276Z",
"queuedTime": "2015-04-27T00:12:15.414Z",
"jobStatus": "Completed",
"jobFolderPath": "/Book/Xslt/Xslt",
"path": "/Book/Xslt/Xslt/27 Apr 2015 10_12_15",
"customer": "",
"name": "27 Apr 2015 10_12_15",
"owner": "Admin",
"labels": [
{
"id": 2147483601,
"name": "Draft",
"owner": "Admin",
"created": "2015-04-27T01:23:51.728Z"
}
],
"duration": 16862,
"outputs": [
"output-1.cxml",
"output-1.indb"
]
}
Post
- If
path
maps to a whole number and cancel is set to true then the job with the specified id is cancelled. - If
path
maps to the path of a job and cancel is set to true then the job with the specified path is cancelled.
Syntax
/api/v1/jobs [path] [cancel=true|false] [customer]
Example Request
POST https://{hostname}/api/v1/jobs/38271673?cancel=true
/api/v1/projects
View projects.
Get
- If
path
maps to a folder then a list of project files within the folder is returned. - If
path
maps to a file then TSS data from the actual file is returned in JSON format.
Syntax
/api/v1/projects [path] [customer]
Example Requests
GET https://{hostname}/api/v1/projects/Guides
GET https://{hostname}/api/v1/projects/Guides.typefi_project
Example Response
{
"workflows": [
"/Travel/City Guides/Index.typefi_workflow",
"/Travel/City Guides/Appendix.typefi_workflow"
]
}
/api/v1/properties
View the server properties. The servlet could be used to
- Check the version number
- Ping the server
- Authenticate a user
Get
The servlet returns the following data
- Server version
- Filestore type (FOLDER or CMS)
- System type (DESKTOP, WORKGROUP or CLOUD)
- A list of customers to which the authenticated user belongs
Syntax
/api/v1/properties [customer]
Example Request
GET https://{hostname}/api/v1/properties
Example Response
{
"version": "8.0.0",
"filestoreType": "FOLDER",
"systemType": "CLOUD",
"customers": [
"acme",
"typefi"
]
}
/api/v1/tss
The TSS servlet is only required if you are creating your own authoring environment. It returns the list of styles for a template or project. Server 7 supported check in of multiple InDesign and TXML files, which were combined to produce a TSS file. In Server 8, the check in process is the same, but instead of TSS a project file is used, containing:
- name, a string
- conditions, an array of strings
- workflows, an array of strings representing workflow file paths.
A template can be one of three file types: InDesign, TXML and CSS. When the TSS servlet is called for a workflow file, every input for every action that corresponds to a template file is returned as JSON. A list of such inputs is returned, unless merge is set to “workflow”, in which case the file contents are returned as a single merged template. All actions with conditions are also returned in the JSON, unless merge is set to “workflow”, in which case the conditions are merged across all actions and returned as a single merged list.
When the TSS servlet is called for a project file, every workflow within the project is converted into JSON, using the approach described previously for single workflow files. If merge is set to "workflow" then, as for single workflow files, within each workflow the contents of the template files are merged and returned as a single merged template, and the conditions within each workflow are returned as a single merged list. If merge is set to "all" then the contents of the template files across all workflows within the project are merged and returned as a single merged template, and all conditions are returned as a single merged list. Otherwise, a list of workflow file contents is returned.
The TSS servlet can also be called directly on template files; their contents are returned as JSON.
Typefi Designer 8.4.0 and later write TXML data into XMP metadata instead of as a separate (sidecar) file. When looking at an InDesign template, if the TXML is available in the XMP metadata then the Server will use that. Otherwise it will fall back on expecting a separate TXML file (for backward compatibility with old templates).
Get
- If
path
maps to a folder then a list of project, workflow and template files within the folder is returned. - If
path
maps to a project, workflow or template file then data from the actual file is returned in JSON format. - If
server
is present then its value is returned as the server property within the TSS. This may be useful for reverse proxy deployments, within which the server may be unable to detect the scheme used to make the request.
Syntax
/api/v1/tss [path] [merge="none"|"workflow"|"all"] [server] [customer]
Example Request
GET https://{hostname}/api/v1/tss/Publish/Publish 7.typefi_project
Example Response
{
"filename": "Appendix.typefi_workflow",
"retrieved": "2015-06-10T22:57:45.750Z",
"actions": [],
"templates": [
{
"filename": "Templates/Template.txml",
"retrieved": "2015-06-10T22:57:46.006Z",
"fields": [],
"conditions": [],
"sections": [
{
"name": "Fixed Element Section",
"fields": [],
"sectionElements": [
{
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Pic2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
]
},
{
"name": "Floating section",
"fields": [],
"sectionElements": []
},
{
"name": "Main Section",
"fields": [],
"sectionElements": []
}
],
"paragraphStyles": [
{
"name": "Michele Para",
"nextStyle": "Michele Para 2"
},
{
"name": "Michele Para 2",
"nextStyle": "Michele Para 2"
}
],
"charStyles": [],
"tables": [
"Table1"
],
"placedElements": [
{
"name": "Fixed Element Pic",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
},
{
"type": "text",
"name": "Elem Field 2"
}
]
},
{
"name": "Fixed Element Words",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
}
]
},
{
"name": "Fixed Sub",
"fields": [
{
"type": "text",
"name": "Elem Field 2"
}
]
}
],
"inlineElements": [
{
"name": "Inline Element",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"name": "Inline Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
],
"floatingElements": [
{
"name": "Floating Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
],
"variants": [
{
"keyword": "Float This 1b"
},
{
"keyword": "Float This 2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
]
},
{
"name": "Floating Text",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Sub",
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
],
"variants": []
}
],
"crossReferenceFormatDefinitions": []
}
]
}
/api/v2/tss
The only change from v1 is the tocStyles list is appended to the template class:
"tocStyles": ["[Default]", "Foo"]
Syntax
/api/v2/tss [path] [merge="none"|"workflow"|"all"] [server] [customer]
Example Request
GET https://{hostname}/api/v2/tss/Publish/Publish 7.typefi_project
Example Response
{
"filename": "Appendix.typefi_workflow",
"retrieved": "2015-06-10T22:57:45.750Z",
"actions": [],
"templates": [
{
"filename": "Templates/Template.txml",
"retrieved": "2015-06-10T22:57:46.006Z",
"fields": [],
"conditions": [],
"sections": [
{
"name": "Fixed Element Section",
"fields": [],
"sectionElements": [
{
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Pic2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
]
},
{
"name": "Floating section",
"fields": [],
"sectionElements": []
},
{
"name": "Main Section",
"fields": [],
"sectionElements": []
}
],
"paragraphStyles": [
{
"name": "Michele Para",
"nextStyle": "Michele Para 2"
},
{
"name": "Michele Para 2",
"nextStyle": "Michele Para 2"
}
],
"charStyles": [],
"tables": [
"Table1"
],
"placedElements": [
{
"name": "Fixed Element Pic",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
},
{
"type": "text",
"name": "Elem Field 2"
}
]
},
{
"name": "Fixed Element Words",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
}
]
},
{
"name": "Fixed Sub",
"fields": [
{
"type": "text",
"name": "Elem Field 2"
}
]
}
],
"inlineElements": [
{
"name": "Inline Element",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"name": "Inline Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
],
"floatingElements": [
{
"name": "Floating Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
],
"variants": [
{
"keyword": "Float This 1b"
},
{
"keyword": "Float This 2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
]
},
{
"name": "Floating Text",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Sub",
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
],
"variants": []
}
],
"crossReferenceFormatDefinitions": [],
"tocStyles": [
"[Default]",
"Foo"
]
}
]
}
/api/v3/tss
Get
The only changes from v2 are:
- 8.5 v3 expands the definition of sections to include the list of master spreads
"sections": [ { "name": "TOC-REG-ISO", "type": "mainStory", "fields": [], "sectionElements": [], "spreads": [ "C-TOC-REG opener", "C-TOC-REG Continued" ] }
- 8.5 v3 adds a "spreads" section
"spreads": [ { "name": "A-Cover-DS", "pages": [ "frames": [ "type": "mainStoryFrame" ], "frames": [] ] }]
Syntax
/api/v3/tss [path] [merge="none"|"workflow"|"all"] [server] [customer]
Example Request
GET https://{hostname}/api/v3/tss/Publish/Publish 7.typefi_project
Example Response
{
"filename": "Appendix.typefi_workflow",
"retrieved": "2015-06-10T22:57:45.750Z",
"actions": [],
"templates": [
{
"filename": "Templates/Template.txml",
"retrieved": "2015-06-10T22:57:46.006Z",
"fields": [],
"conditions": [],
"sections": [
{
"name": "Fixed Element Section",
"type": "mainStory",
"fields": [],
"sectionElements": [
{
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Pic2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
],
"spreads": [
"C-TOC-REG opener",
"C-TOC-REG Continued"
]
},
{
"name": "Floating section",
"fields": [],
"sectionElements": []
},
{
"name": "Main Section",
"fields": [],
"sectionElements": []
}
],
"paragraphStyles": [
{
"name": "Michele Para",
"nextStyle": "Michele Para 2"
},
{
"name": "Michele Para 2",
"nextStyle": "Michele Para 2"
}
],
"charStyles": [],
"tables": [
"Table1"
],
"placedElements": [
{
"name": "Fixed Element Pic",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
},
{
"type": "text",
"name": "Elem Field 2"
}
]
},
{
"name": "Fixed Element Words",
"fields": [
{
"type": "text",
"name": "Elem Field 1"
}
]
},
{
"name": "Fixed Sub",
"fields": [
{
"type": "text",
"name": "Elem Field 2"
}
]
}
],
"inlineElements": [
{
"name": "Inline Element",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"name": "Inline Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
],
"floatingElements": [
{
"name": "Floating Picture",
"fields": [],
"frames": [
{
"type": "imageFrame",
"frames": []
}
],
"variants": [
{
"keyword": "Float This 1b"
},
{
"keyword": "Float This 2",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
}
]
},
{
"name": "Floating Text",
"fields": [],
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Sub",
"frames": [
{
"type": "contentFrame",
"frames": []
},
{
"type": "element",
"name": "Fixed Element Pic",
"frames": [
{
"type": "imageFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "contentFrame",
"frames": []
}
]
},
{
"type": "element",
"name": "Fixed Element Words",
"frames": [
{
"type": "contentFrame",
"frames": []
}
]
}
],
"variants": []
}
],
"crossReferenceFormatDefinitions": [],
"tocStyles": [
"[Default]",
"Foo"
],
"spreads": [
{
"name": "A-Cover-DS",
"pages": [
"frames": [
"type": "mainStoryFrame"
],
"frames": []
]
}]
}
]
}
/api/v1/workflows
View and run workflows. A workflow file is a JSON object containing the name of the workflow along with an array of actions, each of which contains an array of inputs. A workflow which is used to override the input values of a second workflow need only contain a subset of the properties of a workflow: a list of actions, each of which contains type, plugin and inputs properties. Full details are presented in the schemas below.
Schemas
Workflow
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Typefi workflow",
"type": "object",
"required": ["name", "purge", "actions"],
"properties" : {
"name": {
"description": "Workflow name",
"type": "string"
},
"purge": {
"enum": ["Do not purge", "Purge after 7 days", "Purge after 30 days", "Purge after 90 days"]
},
"actions": {
"description": "Actions within the workflow",
"type": "array",
"items": {
"description": "Action within the workflow",
"type": "object",
"required": ["id", "type", "uiVersion", "description", "disabled", "displayname", "inputs", "plugin", "pluginversion"],
"properties": {
"id": {
"description": "Unique identifier",
"type": "integer"
},
"type": {
"description": "Action type",
"type": "string"
},
"uiVersion": {
"description": "User interface version",
"type": "integer"
},
"description": {
"description": "Description of action displayed within user interface",
"type": "string"
},
"disabled": {
"description": "True if action displayed within user interface is disabled",
"type": "boolean"
},
"displayname": {
"description": "Name of action displayed within user interface",
"type": "string"
},
"plugin": {
"description": "Plugin containing the action",
"type": "string"
},
"pluginversion": {
"description": "Version of the plugin containing the action",
"type": "integer"
},
"inputs": {
"type": "array",
"items": {
"description": "Input within the action",
"type": "object",
"required": ["name", "value"],
"properties" : {
"name": {
"description": "Input name",
"type": "string"
},
"value": {
"description": "Input value",
"type": "string"
}
}
}
}
}
}
}
}
}
Overriding Workflow
{
"$schema": "http://json-schema.org/draft-04/schema",
"description": "Typefi workflow",
"type": "object",
"required": ["actions"],
"properties" : {
"actions": {
"description": "Actions within the workflow",
"type": "array",
"items": {
"description": "Action within the workflow",
"type": "object",
"required": ["type", "inputs", "plugin"],
"optional": ["id"],
"properties": {
"type": {
"description": "Action type",
"type": "string"
},
"plugin": {
"description": "Plugin containing the action",
"type": "string"
},
"inputs": {
"type": "array",
"items": {
"description": "Input within the action",
"type": "object",
"required": ["name", "value"],
"properties" : {
"name": {
"description": "Input name",
"type": "string"
},
"value": {
"description": "Input value",
"type": "string"
}
}
}
}
"id": {
"description": "Action id",
"type": "integer"
},
}
}
}
}
}
Get
- If
path
maps to a folder then a list of workflow files and folders within the folder is returned. - If
path
maps to a file then data from the actual file is returned in JSON format. - Filtering by workflow action content type, for example to return only workflows containing docx actions, is not supported since this would require each file to be opened and read to determine whether it contained docx actions.
Syntax
/api/v1/workflows [path] [customer]
Example Requests
// Retrieves the workflows in the specified folder
GET https://{hostname}/api/v1/workflows/London
// Retrieves the specified workflow
GET https://{hostname}/api/v1/workflows/Epub.typefi_workflow
Example Response
{ "actions": [ { "type": "docx-to-cxml", "plugin": "typefi-plugin-docx", "resources": [ "SAXON" ], "displayName": "docx-to-cxml", "id": "1" }, { "type": "cxml-to-indd", "plugin": "typefi-plugin-indd", "resources": [ "indd" ], "displayName": "cxml-to-indd", "id": "2" } ] }
Post
- Runs the workflow.
- The optional multi-part form data is uploaded to the folder created when the workflow is run. Any data which is of image type (for which the mimeType value begins with “image/”, such as “image/png”) is uploaded to a links folder within the folder created when the workflow is run. If imageExtensions contains a list of one or more comma separated values then files that have an extension that is contained within this list are also uploaded to the links folder.
- If
async
is set to true then the id and path of the created job are returned immediately; otherwise, the job is returned as JSON once it has ended, unless return is set to a value matching an output file produced by the workflow, in which case then the named output file is returned in place of the JSON. - A workflow file may optionally be included in the multi-part form data. If such a file is present then its input values override those within the workflow being executed; these input values may be a subset of those within the workflow being executed if only partial overriding is required. If no workflow is specified in the path and a workflow is attached then the attached workflow is executed, with the results being stored in the location specified by path.
Syntax
/api/v1/workflows [path] [async=true|false] [return=name] [imageExtensions=Extension1,Extension2,...,ExtensionN] [customer] [<Multi-part form data>]
Example Requests
// Runs the specified workflow; files to use in the workflow may
// optionally be contained in the multi-part form data
POST https://{hostname}/api/v1/workflows/Epub.typefi_workflow?async=true
Example Response
{
"id": 5340984,
"path": "/2014/Typefi/User Guide Version 8/18 Jan 2014 07_38_40"
}
Examples
Traversing the filestore
Java
import com.jayway.restassured.RestAssured;
/*
* HTTP GET on the /files servlet.
*
* Shows list of files in a folder.
*/
public class Files {
public static void main(String[] args) {
System.out.println(RestAssured
.get("http://localhost:8080/api/v1/files")
.asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Files
{
/*
* HTTP GET on the /files servlet.
*
* Shows list of files in a folder.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080
/api/v1/files");
var request = new RestRequest(Method.GET);
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
Running a simple workflow
Java
import com.jayway.restassured.RestAssured;
/*
* HTTP POST on the /workflows servlet.
*
* Simple case. Just runs a workflow.
*/
public class Workflows1 {
public static void main(String[] args) {
System.out.println(
RestAssured.post("http://localhost:8080
/api/v1/workflows/documentation/workflows
/simple.typefi_workflow").asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Workflow1
{
/*
* HTTP POST on the /workflows servlet.
*
* Simple case. Just runs a workflow.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080
/api/v1/workflows/documentation/workflows
/simple.typefi_workflow");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
The simple.typefi_workflow
file referenced in the above program exists within the Typefi filestore:
{
"name": "simple",
"actions": [
{
"id": "1",
"type": "cxml-to-indd",
"uiVersion": "1",
"description": "Create InDesign Document",
"displayname": "Create InDesign Document",
"inputs": [
{
"name": "input",
"value": "/documentation/content/simple/server.cxml"
},
{
"name": "output",
"value": "simple.indd"
},
{
"name": "template",
"value": "/documentation/templates
/Documentation-Template-PDF-A4.indd"
},
{
"name": "firstPageNumber",
"value": "1"
},
{
"name": "engine",
"value": "CC2015"
},
{
"name": "documentstart",
"value": ""
},
{
"name": "sectionstart",
"value": ""
},
{
"name": "spreadstart",
"value": ""
},
{
"name": "pagestart",
"value": ""
},
{
"name": "spillend",
"value": ""
},
{
"name": "pageend",
"value": ""
},
{
"name": "spreadend",
"value": ""
},
{
"name": "sectionend",
"value": ""
},
{
"name": "indexstart",
"value": ""
},
{
"name": "indexend",
"value": ""
},
{
"name": "documentend",
"value": ""
},
{
"name": "scriptArgs",
"value": ""
},
{
"name": "preserveImageLinks",
"value": "false"
},
{
"name": "softStyle",
"value": "00111111"
},
{
"name": "firstPageSide",
"value": "Left to Right"
},
{
"name": "updateXrefsAtSectionEnd",
"value": "false"
},
{
"name": "updateXrefsAtJobEnd",
"value": "false"
},
{
"name": "tighterFloats",
"value": "false"
},
{
"name": "newFloatOrder",
"value": "false"
},
{
"name": "numMarkersBetweenSaves",
"value": "0"
}
],
"plugin": "typefi-plugin-id",
"pluginversion": "12.0.215",
"disabled": "false"
},
{
"id": "2",
"type": "indd-to-pdf",
"uiVersion": "1",
"description": "Export to PDF",
"displayname": "Export to PDF",
"inputs": [
{
"name": "input",
"value": "simple.indd"
},
{
"name": "output",
"value": "simple.pdf"
},
{
"name": "engine",
"value": "CC2015"
},
{
"name": "preset",
"value": "[High Quality Print]",
"values": [
"[High Quality Print]",
"[PDF/X-1a:2001]",
"[PDF/X-3:2002]",
"[PDF/X-4:2008]",
"[Press Quality]",
"[Smallest File Size]"
]
}
],
"plugin": "typefi-plugin-id",
"pluginversion": "12.0.215",
"disabled": "false"
}
],
"purge": "Do not purge"
}
The simple.typefi_workflow
file referenced in the above program exists within the Typefi filestore and is the same as the previous example.
Overriding parameters in a workflow
Java
import java.io.File;
import com.jayway.restassured.RestAssured;
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and overrides a parameter.
*/
public class Workflows2 {
public static void main(String[] args) {
File workflowOverrides = new
File("/Users/bhauser/overrides.typefi_workflow");
System.out.println(RestAssured.given()
.multiPart(workflowOverrides)
.post("http://localhost:8080/api/v1/workflows
/documentation/workflows/simple.typefi_workflow")
.asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Workflow2
{
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and overrides a parameter.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080/api
/v1/workflows/documentation/workflows
/simple.typefi_workflow");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
request.AddFile("workflow",
@"C:\Users\Desktop\overrides.typefi_workflow");
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
The overrides.typefi_workflow
exists on the client computer running the above program. Overriding workflows can contain all inputs or only a subset, depending upon how many values are to be overridden. The overrides.typefi_workflow
only overrides a single input value:
{
"actions": [
{
"plugin": "typefi-plugin-id",
"type": "cxml-to-indd",
"inputs": [
{
"name": "input",
"value": "/documentation/content/simple
/server-alternate.cxml"
}
]
}
]
}
The id attribute is optional in this subset, but if similar actions can be found in the workflow it is better to put action id as well.
{
"actions": [
{
"id":2,
"plugin": "typefi-plugin-id",
"type": "cxml-to-indd",
"inputs": [
{
"name": "input",
"value": "/documentation/content/simple
/server-alternate.cxml"
}
]
}
]
}
Attaching client files to a workflow
Java
import java.io.File;
import com.jayway.restassured.RestAssured;
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and attaches custom cxml from the client side.
*/
public class Workflows3 {
public static void main(String[ ] args) {
File cxml = new File("/Users/bhauser/client.cxml");
System.out.println(RestAssured.given()
.multiPart(cxml)
.post("http://localhost:8080/api/v1/workflows
/documentation/workflows/simple.typefi_workflow")
.asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Workflow3
{
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and attaches custom cxml
* from the client side.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080/api
/v1/workflows/documentation/workflows
/simple.typefi_workflow");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
request.AddFile("cxml",
@"C:\Users\Desktop\client.cxml");
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
The client.cxml
file referenced in the above program exists on the client computer. When the workflow is run the file is copied into the job folder; the workflow must therefore reference it using a job folder path. Such paths are not preceded by any parent folders or slashes, and in this case would be client.cxml.
Attaching client files to a workflow and overriding parameters in a workflow
Java
import java.io.File;
import com.jayway.restassured.RestAssured;
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and attaches custom cxml
* from the client side and overrides a parameter.
*/
public class Workflows4 {
public static void main(String[] args) {
File cxml = new File("/Users/bhauser/client.cxml");
File workflowOverrides = new
File("/Users/bhauser/overrides.typefi_workflow");
System.out.println(RestAssured.given()
.multiPart(cxml)
.multiPart(workflowOverrides)
.post("http://localhost:8080/api/v1/workflows
/documentation/workflows/simple.typefi_workflow")
.asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Workflow4
{
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and attaches custom cxml
* from the client side and overrides a parmeter.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080
/api/v1/workflows/documentation/workflows
/simple.typefi_workflow");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
request.AddFile("cxml",
@"C:\Users\Desktop\client.cxml");
request.AddFile("workflow",
@"C:\Users\simple.typefi_workflow");
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
The program above combines the previous two examples, attaching the client files client.cxml
and overrides.typefi_workflow
.
Attaching everything
Java
import java.io.File;
import com.jayway.restassured.RestAssured;
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and overrides everything.
*/
public class Workflows5 {
public static void main(String[] args) {
File cxml = new File("/Users/bhauser/content.cxml");
File indd = new File("/Users/bhauser/template.indd");
File txml = new File("/Users/bhauser/template.txml");
File workflow = new File("/Users/bhauser
/workflow.typefi_workflow");
System.out.println(RestAssured.given()
.multiPart(cxml)
.multiPart(indd)
.multiPart(txml)
.multiPart(workflow)
.post("http://localhost:8080/api/v1/workflows
/client side jobs/deeper/and/deeper")
.asString());
}
}
C#
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Typefi_API_Demo
{
internal class Workflow5
{
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow and overrides everything.
*/
private static void Main(string[] args)
{
var client = new RestClient("http://localhost:8080/api
/v1/workflows/client side jobs
/deeper/and/deeper");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
request.AddFile("cxml",
@"C:\Users\Desktop\content.cxml");
request.AddFile("indd",
@"C:\Users\Desktop\template.indd");
request.AddFile("txml",
@"C:\Users\Desktop\template.txml");
request.AddFile("workflow",
@"C:\Users\Desktop\workflow.typefi_workflow");
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
Console.ReadKey();
}
}
}
In the above program the workflow and input files do not exist on the Typefi server before execution; instead, they are all attached. When the workflow executes, the files content.cxml
, template.indd
and template.txml
are sent to the server along with the workflow.typefi_workflow
workflow file. The folder /client side jobs/deeper/and/deeper
is created on the Typefi server if it does not already exist, and the workflow is run within this folder. As with the previous examples, the workflow paths refer to the files within the job folder, and so are content.cxml
, template.indd
and template.txml
.
Polling an asynchronous request for status
Java
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.time.Instant;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.response.Response;
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow asynchronously, polls for status
* and downloads the output file.
*/
public class Workflows6 {
public static void main(String[] args) {
try {
run();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void run() throws InterruptedException,
IOException {
// ---------------------------------------------------------
// 1. Run the workflow
log("Running workflow");
Response response = RestAssured.post(
"http://localhost:8080/api/v1/workflows
/documentation/workflows
/getting-started-with-typefi-8.typefi_workflow?async=true");
System.out.println(response.asString());
Integer id = response.path("id");
log("Job id: " + id);
// ---------------------------------------------------------
// 2. Poll for job status
String status;
do {
response = RestAssured
.get("http://localhost:8080/api/v1/jobs/" + id);
System.out.println(response.asString());
status = response.path("jobStatus");
log("Job status: " + status);
Thread.sleep(1000);
} while (!status.equalsIgnoreCase("Completed"));
String path = response.path("path");
// ---------------------------------------------------------
// 3. Download the PDF
log("Downloading PDF");
response = RestAssured
.get("http://localhost:8080/api/v1/files" +
path + "/Getting started with Typefi 8.pdf");
// ---------------------------------------------------------
// 4. Write the PDF to the local filesystem
log("Writing PDF to local filesystem");
File tmp = File.createTempFile("output", ".pdf");
java.nio.file.Files.write(tmp
.toPath(), response.asByteArray());
// ---------------------------------------------------------
// 5. Open the PDF in the system default viewer
log("Opening PDF");
Desktop.getDesktop().open(tmp);
log("Done");
}
private static void log(String s) {
System.out.println(Instant.now() + " " + s);
}
}
C#
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using RestSharp.Authenticators;
using System;
using System.IO;
using System.Net;
namespace Typefi_API_Demo
{
internal class Workflow6
{
/*
* HTTP POST on the /workflows servlet.
*
* Runs a workflow asynchronously, poll for
* status and downloads the output file.
*/
private static void Main(string[] args)
{
// ----------------------------------------------------
// 1. Run the workflow
var client = new RestClient("http://localhost:8080/api
/v1/workflows/documentation/workflows
/getting-started-with-typefi-8.typefi_workflow
?async=true");
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
var request = new RestRequest(Method.POST);
RestResponse response = client.Execute(request)
as RestResponse;
String content = response.Content;
Console.WriteLine(content);
JObject data = JObject.Parse(response.Content);
string id = (string)data["id"];
// ----------------------------------------------------
// 2. Poll for job status
string status = null;
do
{
client = new RestClient("http://localhost:8080
/api/v1/jobs/" + id);
client.Authenticator = new
HttpBasicAuthenticator("User_Name", "Password");
request = new RestRequest(Method.GET);
response = client.Execute(request) as RestResponse;
data = JObject.Parse(response.Content);
content = response.Content;
status = (string)data["jobStatus"];
} while (status != "Completed");
// ----------------------------------------------------
// 3. Download the PDF
String path = (string)data["path"];
string link = ReplaceEmptySpace("http://localhost:8080
/api/v1/files" + path +
"/Getting started with Typefi 8.pdf");
WebClient webClient = new WebClient();
webClient.Credentials = new
NetworkCredential("User_Name", "Password");
// ----------------------------------------------------
// 4. call "DownloadCompleted" when download completed
webClient.DownloadDataCompleted += new
DownloadDataCompletedEventHandler(DownloadCompleted);
webClient.DownloadDataAsync(new Uri(link));
Console.Write(content);
// ----------------------------------------------------
Console.ReadKey();
}
// Replace empty spaces with "%20"
private static string ReplaceEmptySpace(string text)
{
text = text.Replace(" ", "%20");
return text;
}
private static void DownloadCompleted(object sender,
DownloadDataCompletedEventArgs e)
{
if (e.Error == null)
{
byte[] bytes = e.Result;
// 5. Write the PDF to the local filesystem
File.WriteAllBytes(
@"C:\Users\Desktop\output.pdf", bytes);
// 6. Open the PDF in the system default viewer
System.Diagnostics.Process.Start(
@"C:\Users\Desktop\output.pdf");
}
}
}
}
All the workflows prior to that used by the above program ran synchronously, returning JSON to the client once their execution was complete. In the first step of the above example the workflow is run with the async parameter set to true; its job id is therefore returned immediately. In the second step the job servlet is polled for the status of this job, until this has the value "Completed". When the job has completed, the third step uses its path (returned by the job servlet) to retrieve its pdf output via the files servlet. The pdf is written to the client file system in the fourth step, and in the fifth the pdf file is opened using the default viewer.
/api/v2/workflows
Get
Version 2 of the workflows servlet is identical to version 1, except that:
- v2 is used in place of v1 within the url
- the
imageExtensions
parameter for post requests is renamed tolinkExtensions
.
/api/v3/workflows
Get
- 8.5 Added a new attribute called
label
in the inputs array to get the label values of the input UIs.
Example Response
[
{
"id": "2",
"type": "addlabel",
"hastabs": "false",
"description": "Add tag",
"displayname": "Add tag",
"uiVersion": "2",
"plugin": "typefi-plugin-util",
"pluginversion": "125",
"disabled": "false",
"inputs": [
{
"name": "label",
"value": "${job-folder}",
"label": "entrada"
},
{
"name": "label",
"value": "output",
"label": "salida"
}
]
}
]
Post
- 8.10 Introduced an optional
unzip=true|false
parameter. This parameter controls whether to automatically unzip attached files and extract them to the job folder after upload. - 8.10 Added a webhook parameter that allows you to specify a URL to communicate with external systems and send real-time job status notifications during workflow progress tracking.
Syntax
/api/v3/workflows [path] [async=true|false] [return=name] [unzip=true|false]
[imageExtensions=Extension1,Extension2,...,ExtensionN] [customer]
[webhook url] [<Multi-part form data>]
Example requests
// Unzips all the attached zip files and places the extracted files into the job folder.
POST https: //{hostname}/api/v3/workflows/Epub.typefi_workflow?unzip=true
// Receive real-time job status updates at a specific webhook URL:
POST https: //{hostname}/api/v3/workflows/Epub.typefi_workflow?customer=Typefi&webhook=https://your-webhook-url.com
// Disable webhook notifications by omitting the URL:
POST https: //{hostname}/api/v3/workflows/Epub.typefi_workflow?customer=Typefi
Example response
{
"id": ""}
{
"Job Status": "Job Completed"
}
Comments
9 comments
The embedded Vimeo video in this technical resource article is private (it is password protected and unless a person knows the password, it is pretty much useless).
Thanks for letting us know. I've updated the article to point to the correct Vimeo video.
Hi Celeb,
Please update this article according to 8.4 API.
Thanks,
Gaurav Gupta
We're working on updating all our documentation for Typefi 8.4.
Hi Caleb,
Any timeline, when we can get the documentation.
Thanks,
Gaurav Gupta
This documentation is now up to date with version 8.6 of Typefi server.
– Guy
Hi, would be great if the examples could be updated to use the latest versions (eg.
We got tripped up by doing a copy-and-paste.
Hi Gregg, we're sorry that the examples were not up-to-date, causing you to get tripped up. All examples are now updated with the latest versions. Thanks for bringing this to our attention.
You might want to update restassured java references to now use io.restassured. Current version is 4.4.
Please sign in to leave a comment.