3

How can I add a new document to Content Server 10.5 using the REST api?

I am following the Swagger docs for creating a node, but it is not clear how I attach the file to the request. Here is (roughly) the code I am using:

var folderId = 2000;
var docName = "test";

var uri = $"http://[serverName]/otcs/llisapi.dll/api/v1/nodes?type=144&parent_id={folderId}&name={docName}";    

var request = new HttpRequestMessage();
request.Headers.Add("Connection", new[] { "Keep-Alive" });
request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate"); 
request.Headers.Add("Pragma", "no-cache");     
request.Headers.Add("OTCSTicket", /* ticket here */);
request.RequestUri = new Uri(uri);
request.Method = HttpMethod.Post;
request.Content = new ByteArrayContent(data);
request.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping(filePath));
request.Headers.ExpectContinue = false;

var httpClientHandler = new HttpClientHandler
{
  Proxy = WebRequest.GetSystemWebProxy(),
  UseProxy = true,
  AllowAutoRedirect = true
};

using (var client = new HttpClient(httpClientHandler))
{
  var response = client.SendAsync(request).Result;
  IEnumerable<string> temp;
  var vals = response.Headers.TryGetValues("OTCSTicket", out temp) ? temp : new List<string>();
  if (vals.Any())
  {
    this.ticket = vals.First();
  }

  return response.Content.ReadAsStringAsync().Result;
}

I've been searching through the developer.opentext.com forums, but finding a complete example in c# is proving tough - there are a few examples in javascript, but attempting to replicate these in c# or via chrome or firefox extensions just give the same results. Calling other CS REST methods has not been an issue so far, this is the first one that's giving me problems.

Edit: I pasted the wrong url into my question, which I've now fixed. It was var uri = $"http://[serverName]/otcs/llisapi.dll/api/v1/forms/nodes/create?type=0&parent_id={folderId}&name={docName}";.

meataxe
  • 969
  • 13
  • 33
  • I updated the url as per Steffen's question, but I'm still getting 400 bad request errors. Are there any logs I can check to see what might be going wrong. I also saw something about the CS UI widgets - where are they and how might they help? – meataxe Dec 29 '15 at 07:11
  • I'm just re-reading your question. I noticed that you've packed the parameters into the url. But you want to perform a POST, therefore all those parameters have to go into the body. – Steffen Roller Jan 05 '16 at 20:06

4 Answers4

2

Your URL doesn't look like the REST API, it's rather the traditional URL used for the UI.

This article should describe how to do what you want to do:

https://developer.opentext.com/webaccess/#url=%2Fawd%2Fresources%2Farticles%2F6102%2Fcontent%2Bserver%2Brest%2Bapi%2B%2Bquick%2Bstart%2Bguide&tab=501

EDITED:

Ok, so that's how it should work:

send a POST to http://www.your_content_server.com/cs[.exe]/api/v1/nodes

send this in your payload to create a document in your enterprise workspace

type=144
parent_id=2000
name=document_name.txt
<file>

A incomplete demo in Python would look like this. Make sure you get a valid ticket first.

files = {'file': (open("file.txt", 'rb')}
data = { 'type': 144, 'parent_id': 2000, 'name': 'document_name.txt' }
cs = requests.post(url, headers={'otcsticket':'xxxxxxx'}, data=data, files=files)
if cs.status_code == 200:
    print "ok"
else:
    print cs.text
Steffen Roller
  • 3,464
  • 25
  • 43
  • 3
    This is what I've found frustrating - the swagger docs and the quickstart guide seem at odds with each other. The swagger docs state the type, parent id and name should be on the querystring, but the quickstart state they should be in the request body. Neither of them mention how to attach the actual file to upload. What would be ideal is a working c# or javascript example. I'm still getting 400 errors back and they aren't enough to point me in the right direction. – meataxe Dec 29 '15 at 07:08
  • how to add BuilingId to request .tried below data = { 'type': 144, 'parent_id': 2000, 'name': 'document_name.txt' ,'BuilingId ': 'xxxx'} showing following error "BuilingId is a required field." – user202 Aug 16 '17 at 13:18
1

You will need a form input to get the file onto the page then you can use filestreams to redirect it, there is great guide for that here.

Reading files in JavaScript using the File APIs

Here is a Jquery/ Ajax example.

I find the best way to go about this is to use Postman (Chrome Plugin) to experiment until you get comfortable.

var form = new FormData();
form.append("file", "*filestream*"); 
form.append("parent_id", "100000");
form.append("name", "NameYourCreatedFile");
form.append("type", "144");

var settings = {
  "async": true,
  "url": "/cs.exe/api/v1/nodes", // You will need to amend this to match your environment
  "method": "POST",
  "headers": {
    "authorization": "Basic **use Postman to generate this**",
    "cache-control": "no-cache",
  },
  "processData": false,
  "contentType": false,
  "mimeType": "multipart/form-data",
  "data": form
}

$.ajax(settings).done(function (response) {
  console.log(response);
});
platinums
  • 634
  • 1
  • 10
  • 21
0

It appears that the OpenText API only supports file uploads through asynchronous JavaScript uploads - not through traditional file uploads by using typical posted form requests that contain the files contents (which is pretty crappy to be honest - as this would be the easiest to handle on server side).

I've contacted their support and they were absolutely no help - they said since it's working with JavaScript, then they can't help me. Anyone else utilizing any language besides JavaScript is SOL. I submitted my entire API package, but they didn't bother investigating and wanted to close my ticket ASAP.

The only way I've found to do this, is to upload / send the file into your 'Upload' directory on your Content Servers web server (on ours it was set to D:\Upload).This directory location is configurable in the admin section.

Once you've sent the file to your web server, send a create node request with the file param set to the full file path of the file residing on your server, as the OpenText API will attempt to retrieve the file from this directory.

I've created a PHP API for this, and you can browse its usage here:

https://github.com/FBCLIT/OpenTextApi

<?php

use Fbcl\OpenTextApi\Client;

$client = new Client('http://server.com/otcs/cs.exe', 'v1');

$api = $client->connect('username', 'secret');

try {
    // The folder node ID of where the file will be created under.
    $parentNodeId = '12356';

    // The file name to display in OpenText
    $fileName = 'My Document.txt';

    // The actual file path of the file on the OpenText server.
    $serverFilePath = 'D:\Upload\My Document.txt';

    $response = $api->createNodeDocument($parentNodeId, $fileName, $serverFilePath);

    if (isset($response['id'])) {
        // The ID of the newly created document will be returned.
        echo $response['id']; 
    }   
} catch (\Exception $ex) {
    // File not found on server drive, or issue creating node from given parent.
}

MIME Type detection appears to happen automatically, and you do not need to send anything for it to detect the file type. You can name the file to whatever you like without an extension.

I have also discovered that you cannot use an IP address or Host name for uploading files in this manor. You must enter a path that is local to the server you are uploading to. You can however give just the file name that exists in the Upload directory, and the OpenText API seems to locate it fine.

For example, you can pass either D:\Uploads\Document.txt or Document.txt.

If you haven't done it correctly, you should get the error:

Client error: POST http://server.com/otcs/cs.exe/api/v1/nodes resulted in a 400 Bad Request response: {"error":"Error: File could not be found within the upload directory."}

Steve Bauman
  • 8,165
  • 7
  • 40
  • 56
0

Answering my own question, but with powershell 5 (eg. without the -Form parameter):

<#
    .SYNOPSIS
        Adds a new document to a folder in Content Server.        
    .DESCRIPTION
        Adds a new document to a folder in Content Server. Will fail
        if a document of the same name already exists in the folder.
    .PARAMETER Url
        String. Required. The first part of the url of the OTCS server. Eg. 'https://url.to.server'          
    .PARAMETER Ticket
        String. Required. Ticket from a call to '/otcs/llisapi.dll/api/v1/auth'.
    .PARAMETER Source
        String. Required. Path to the file to add.
    .PARAMETER ParentFolderID
        Long. Required. The DataID of the destination folder in Content Server.
    .EXAMPLES
        Get-OTCSDocument -Server [ServerName] -Ticket '?' -ParentFolderID 1234 -Source 'c:\path\to\file.txt' 
#>
Function Add-OTCSDocument ($Url, $Ticket, $ParentFolderID, $Source)
{
    $docResult = @{ Success = $false; DocumentID = 0; ExceptionStatusDescription = $null }    
    $fileName = Split-Path $Source -leaf
    
    $AddDocumentUrl = "$Url/otcs/llisapi.dll/api/v1/nodes"

    $header = @{ otcsticket = $ticket }
    
    $CODEPAGE = "UTF-8" # alternatives are ASCII, iso-8859-1 
    $enc = [System.Text.Encoding]::GetEncoding($CODEPAGE)
    $fileBin = [System.IO.File]::ReadAllBytes($Source)
    $fileEnc = $enc.GetString($fileBin)
    $fileName = Split-Path $Source -leaf

    $boundary = [System.Guid]::NewGuid().ToString()       

    $LF = "`r`n"
    $bodyLines = (
        "--$boundary",
        "Content-Type: text/plain; charset=utf-8",
        "Content-Disposition: form-data; name=body$LF",
        "{ `"type`":144, `"name`":`"$fileName`", `"parent_id`":$ParentFolderID }",        
        "--$boundary",
        "Content-Disposition: form-data; name=file; filename=$fileName",
        "Content-Type: application/octet-stream$LF",        
        $fileEnc,
        "$LF",
        "--$boundary--$LF"
     ) -join $LF
    
    Try {
      $result = Invoke-RestMethod -Uri $AddDocumentUrl -ContentType "multipart/form-data; boundary=`"$boundary`"" -Method Post -Headers $header -Body $bodyLines;      
        
      $docResult.Success = $true
      $docResult.DocumentID = $result.id                    
      
      Write-Host $result
    } Catch {
      if($_.ErrorDetails.Message) {
        Write-Host $_.ErrorDetails.Message
      } else {
        Write-Host $_
      }

      $docResult.ExceptionStatusDescription = $_.Exception.Response.StatusDescription
    }
    
    $docResult
}
meataxe
  • 969
  • 13
  • 33