Child pages
  • SaveDocument
Skip to end of metadata
Go to start of metadata

Description

The SaveDocument API allows a User to save or update a Document with the given parameters.

In apstrata, data and digital assets are grouped into Documents, where each Document corresponds to a collection of name-value pairs known as fields. Each field within a Document has a type and can be specified to be indexed for full text searching.

In addition to the data itself, a Document contains metadata information such as the creator, creation time, last modification time, etc.

Documents may have Schemas defining their structure, in a declarative way, in terms of field groups, field types, field validations and field groups ACLs. Apstrata does not enforce the use of Schemas when persisting Documents. However, in this case, no security or validation rules can be applied at the level of the fields.

Each Document is persisted in a Store with a key that uniquely identifies it within that Store.

All Documents saved in an apstrata Store are secured individually with ACLs (from wikipedia: Access Control Lists), allowing developers to specify the Users and/or Groups that can view, update or delete a Document, or more granularly individual fields within that Document.

A developer can create as many Documents as needed per Store. However, there is a limit on the number of fields a Document can have, as well as on the size of digital assets within that Document. This limit is based on the apstrata account type that a developer has.

A developer can choose to create multiple versions of a certain Document. Each Document version is identified by a number which is automatically assigned to it upon creation time. This number is equivalent to the last version number of the Document plus one. At any point in time, a developer can retrieve a particular version of a Document. However, only the latest version of a Document can be updated. Reverting back to an old version of a Document simply means creating a new version with the data retrieved from that old version.

There are two ways to save a document - with an defined schema, or without one. Users wanting more flexibility and control over files and security should create documents with a schema.

Note that “schema-less” documents are actually documents with a default schema. This default schema contains the field "apsdb_attachments" that can be used to attach a file to the schema-less document.

Creating Documents

To create a document, users should create fields that make up this document. Creating a field can be done by providing [fieldname]=[fieldValue] pairs and setting the apsdb.multivalueAppend parameter=[fieldname] to append multiple values else the last value of the fieldname will be set only.

When specifying fields, users can send a fieldType. This will ensure the field value will be parsed and validated. The fieldType defaults to "string" if not sent. Any other values than the predefined types (string, text, numeric, date, file, geospatial) are not allowed.

Note that all fieldNames starting with apsdb or ending with apsdb.fieldType or apsdb.fieldDateFormat cannot be sent more than once, else an error (DUPLICATE_PARAMETER_VALUE) will be returned.

When saving a document, it should be specified to what store it is saving. When saving a document, users can send a document key. If the key is not sent, then apstrata database will generate a store-bound unique id, called a document key, for each document. This key will be used when updating the document later.

Please remember that apstrata database uses the document key to index its documents, so it is necessary to have random document keys. More importantly, the first few letters of the document key should be random and unique. The reason for random document keys is to optimize the indexing process and make your data storage and retrieval operations faster. For example:

Good document keys:

123_john, 234_john, 345_john, 456_john, …

Bad document keys:

john_123, john_234, john_345, john_456, …

Field of type 'date':
When saving a field of type 'date', the system needs to know the format used to parse the date sent in the request. There are three ways to do so:

1- Use the default system format:
The system accepts two date formats by default:
yyyy-MM-dd'T'HH:mm:ssZ (e.g. 2012-04-13T13:01:02+0000)
yyyy-MM-dd (e.g. 2012-04-13)
Unless otherwise specified, the fields of type 'date' sent in the SaveDocument request will be expected to use one of the two default formats and will be parsed accordingly.
An error is returned if the date does not match either of these formats.
Below is an example of a javascript implementation that generates a date in the default system format:
new Date().toISOString().split(".")[0]+"+0000"

2- Use the apsdb.globalDateFormat request parameter:
Sending the apsdb.globalDateFormat parameter in the SaveDocument request informs the system to expect all 'date' fields of the current document to use the specified format. The dates will be parsed using this new format and an error will be returned if one of the fields cannot be parsed.
The format specified in the apsdb.globalDateFormat parameter always overrides the default system date format for the current document.

3- Use the [fieldName].apsdb.fieldDateFormat request parameter:
Sending a date format in the [fieldName].apsdb.fieldDateFormat parameter informs the system that the value of field [fieldName] uses the specified format and should be parsed accordingly. If the format of the date sent in this field is not the one specified in the parameter then an error will be returned.
The format specified in the [fieldName].apsdb.fieldDateFormat parameter always overrides both the default system date format and the format sent in the apsdb.globalDateFormat parameter for the specified field ([fieldName]).

Please note that the server time is GMT.

Field of type 'file':

Saving a field of type "file" is done differently if the document is bound to a schema or not.

1- Document is schemaless:
Only the special field "apsdb_attachments" can be used to save a file to a document that is not bound to a schema. It is possible to attach multiple files to the "apsdb_attachments" field by sending its name in the apsdb.multivalueAppend parameter (ex:  apsdb.multivalueAppend=apsdb_attachments).
If a user sends a file in a different field than “apsdb_attachments”, an error will occur with code "INVALID_FIELD_VALUE".

2- Document is bound to a schema:
If the document being saved is bound to a schema then files can only be saved under fields of type "file" defined in the schema. Trying to save a file under a field that is not defined in the schema or under the special field "apsdb_attachments" will result in an error with code "FIELD_FILE_NOT_DEFINED".

To save a file to a document, you need to send it in a multipart request. This can either be done in an HTML form with an input of type “file” representing the field under which the file will be saved (ex: <input type=”file” name=”myFileFieldName”>) or by sending a raw HTTP request as follows:

POST /apsdb/rest/[authenticationkey]/SaveDocument?apsws.time=1245681044 &apsws.authSig=5cf178fed074ec9dfa202627d860123f0e7daf0f HTTP/1.0
Host: sandbox.apstrata.com
Content-Type: multipart/form-data; boundary=---------------------e7b6ef072f
Content-length: 1516
-----------------------e7b6ef072f
Content-Disposition: form-data; name="apsdb.documentKey"
documentKey
-----------------------e7b6ef072f
Content-Disposition: form-data; name="apsdb.store"
myStore
-----------------------e7b6ef072f
Content-Disposition: form-data; name="newNumericField4"
1200
-----------------------e7b6ef072f
Content-Disposition: form-data; name="newNumericField4"
1100
-----------------------e7b6ef072f
Content-Disposition: form-data; name="newNumericField4.apsdb.fieldType"
numeric
-----------------------e7b6ef072f
Content-Disposition: form-data; name="field1"
myField1
-----------------------e7b6ef072f
Content-Disposition: form-data; name="field1.apsdb.fieldType"
string
-----------------------e7b6ef072f
Content-Disposition: form-data; name="apsdb_attachments"; filename="myFile.txt"
Content-Type: application/octet-stream
my
 file contents, my file contents, my file contents, my file contents, my
 file contents, my file contents, my file contents, my file contents,
my
 file contents, my file contents, my file contents, my file contents, my
 file contents, my file contents, my file contents, my file contents
-----------------------e7b6ef072f
Content-Disposition: form-data; name="apsdb.ftsFields"
newNumericField4,field1,apsdb_attachments
 
 
-----------------------e7b6ef072f--

Field of type 'geospatial':

Saving a field of type "geospatial" requires providing a pair of longitude and latitude coordinates represented in decimal degrees.

[fieldname]=[LATITUDE],[LONGITUDE]

Where LATITUDE  and LONGITUDE should match numbers that have at most 3 digits before a decimal and 4 digits after, and optionally leading + or -.

Example:
EiffelTowerCoordinates = 48.8580,2.2951

StatueOfLibertyCoordinates =40.6892,-74.0447

 

Creating A Scheduling Document

A scheduling document contains a defined set of reserved fields that control the execution of a script at a specific date and time.

Fields NameDescription

apsST_scriptName

The name of the script to be scheduled

apsST_execAt

The date and time at which the script will run

apsST_execAt.apsdb.fieldType

This should be set to "date" to indicate the type of the apsST_execAt field

apsST_saveResult

A boolean indicating whether to save the result of calling the script in the scheduling document

Please refer to Scheduled Script for more details about scheduling scripts.

Updating a document

Documents submitted for updating must include the document key of the document apsdb.documentKey=[key]. The update parameter can take the following values: [true|false]. Any different value will not be allowed.

The update parameter apsdb.update and the document key parameter apsdb.documentKey are handled in the following way when sent:

 

and update parameter is not sent

and update parameter is set to true

and update parameter is set to false

In case a document key is not sent…

create a document

not allowed

create a document

In case a document key is sent empty…

not allowed

not allowed

not allowed

In case a document key is sent that maps to an existing document…

update the document

update the document

not allowed

In case a document key is sent that doesn’t map to an existing document…

create a document

not allowed

create a document

When updating a field in a document, if the user tries to append to an existing value, the value type should match the existing field type or else the request will not be allowed. Note, however, that replacing the existing value with a new value of a different type is allowed. Replacing a value is done by sending a request with the document key and the same fieldName with a different value. Note, however, that updating a multivalue field to a single value will remove the multivalue fields.

If the user wishes to append to an existing field in an existing document, he can send the new values and set the apsdb.multivalueAppend to this fieldname. apsdb.multivalueAppend should contain a comma separated list of fieldNames the user wishes to append.

Appending will only add unique values to one field. If the user tries to create a duplicate field value, the action is ignored. Appending to a single value will make the field multivalued.

Users cannot append more than one file attachment per field, but can attach more than one file per document by creating multiple file attachment fields.

Deleting a field or a field value

Finally, to delete a field (single or multi-valued), the update request should send the field with an empty value. Note that deleting a field will delete all its values by sending fieldName with no value (e.g. apsdb.fieldName=)

Users can also delete fields by sending fieldName.apsdb.delete=valueToBeDeleted.

If the user sends fieldName.apsdb.delete with no value, the field with all its values will be deleted.

ACLs

When saving a document, field ACLs are verified

  • Adding fields in the fts fields to be indexed cannot be done on fields the user doesn't have read access on
  • Saving fields the user doesn't have write access on is not allowed
  • Saving file fields the user doesn't have write access on is not allowed
  • If a user has no write access to any field group including the dynamic fields, then he may not create/update a document.

Note: if you try to create/ or update a schema-less document but the configuration of your account does not allow for schema-less documents, you will get a "PERMISSION_DENIED" error  when calling "SaveDocument" even if your credentials are valid.

Overriding Schema and Default ACLs

In specific cases, the need to override ACLs set in the schema is required. One example of an application with such a use case is a wiki. First, let’s assume that all wiki pages are documents based on the same schema. Let us also assume that the schema allows only the creator to write to the wiki pages.

However, someone who created a page in a wiki may require adding contributors to help him update the page and write to it. This is the case where the user would need to override the ACLs set in the schema and give write ACLs to contributors. Please find the below example to better explain this concept.

<schema>
    <aclGroups>
     <aclGroup name="wikiPage">
         <read>all</read>
         <write>creator</write>
         <fields>
             <field>field1</field>
             <field>picture</field>
         </fields>
     </aclGroup>
     <defaultAcl>
         <read>all</read>
         <write>creator</write>
     </defaultAcl>
     <schemaAcl>
         <read>user1;user2;group:group1</read>
         <write>user1;user2;group:group1</write>
         <delete>user1;user2;group:group1</delete>
     </schemaAcl>
</aclGroups>
<fields>
     <field name="field1" type="string" />
     <field name="picture" type="file" />
</fields>
</schema>


The ACLs in the documents will take priority over the ones in the schema. So in order to override the ACLs in the “wikiPage” ACL group, the user can send wikiPage.writeACL parameter in the request. In order to override default ACLs, the user can send default.readACL or default.writeACL parameters in the request. To override the default delete ACL, the user must send document.deleteACL parameter in the request. Moreover, the document.readACL and document.writeACL parameters can be used to grant or deny read and write access to the document as a whole, and they override the field groups and dynamic fields (default) ACLs.

The following are the possible scenarios for overriding schema ACLs:

  • A user who is in the "document writeACL" can modify who else is in the "document writeACL" and "document readACL"
  • A user who is in the "document deleteACL" can modify who else is in the "document deleteACL"
  • A user who is in the "default writeACL" can modify who else is in the "default writeACL" and "default readACL"
  • A user who is in a "field group writeACL" can modify who else is in the "field group writeACL" and "field group readACL"

The following are the possible scenarios for overriding "schema-less" ACLs:

  • A user who is in the "document writeACL" can modify who else is in the "document writeACL" and "document readACL"
  • A user who is in the "document deleteACL" can modify who else is in the "document deleteACL"

Note that for "schema-less" documents, the "default writeACL" and the "default readACL" are meaningless. Instead, the "document writeACL" and the "document writeACL" should be used. In "schema-less" documents, all fields are supposed to be dynamic fields. However, and for technical reasons, the attached files fields cannot be dynamic, and hence needed to be defined in a field group in the default schema. This means that even if you try to override the "default readACL" and "default writeACL", this does not affect attached files fields. As a result, you are supposed to use the "document readACL" and "document writeCL" instead.

Also note that the "document writeACL" restricts EVERYTHING. That is, if a user is NOT in the "document writeACL", then he cannot do anything on the document even though he is a member of other ACLs. By default, the "document readACL" and "document writeACL" imply everyone in case they are not set.

Last but not least, the following rules apply for viewing the ACLs persisted with the document:

  • A user who is in the "document readACL" can view the "document writeACL" and "document readACL" and "document deleteACL"
  • A user who is in the "default readACL" can view the "default writeACL" and "default readACL"
  • A user who is in a "field group readACL" can view the "field group writeACL" and "field group readACL"

Versioning

Versioning is an extra step that may occur when updating a document. It can be used to keep track of all changes to a document or to create new versions of a document at specific milestones.

A document is uniquely identified by its dockey and version number. Multiple versions of the same document have the same dockey, but different version numbers.

A document's schema may specify the type of versioning that the document supports. (Schemaless documents have disabled versioning). API calls to SaveDocument may use the following parameters to take advantage of this feature: apsdb.versioning and apsdb.latestVersion. Note that the first time a document is created, it is by default the first version. The versioning parameters should not be used when creating this first version --- versioning requires the apsdb.update parameter to also be true.

The apsdb.versioning parameter specifies whether this call of SaveDocument should create a new version of the document instead of updating the existing document.
The apsdb.latestVersion parameter specifies what is currently expected to be the latest version of the document. If it does not match what the actual latest version is, then the SaveDocument call will fail with a CANNOT_CREATE_VERSION ServiceException.

If you are not creating a new version of a document or if you are creating a new document, but you also specify the apsdb.latestVersion parameter, then an INVALID_REQUEST ServiceException will be thrown.

Schema VersioningSaveDocument Result
DisabledThis document (or any other document that follows the schema) cannot be versioned and will be updated instead.
ForcedA new version of the document will be created.
EnabledA new version of the document will be created if the parameter apsdb.versioning is true, else the current document will be updated.

Anything that causes a contradiction to the above table will lead to an INVALID_PARAMETER_VALUE ServiceException being thrown. For instance, if versioning is disabled, but the apsdb.versioning parameter is sent as true, or if versioning is forced but apsdb.versioning is false, etc.

Note that the latest version of the document will inherit all ACLs from its previous version. If the previous version contains a document.writeACL that differs from the one specified in its schema, then the current values of its document.writeACL field will be saved under a new field called document.writeACL.previous, and its document.writeACL will be set to "nobody". This results in old versions  read-only, and a backup of the writeACL that was used. The following example illustrates this behavior:

Before VersioningDocument Version 1
document.writeACL = "user1"
Document Version 2
does not exist yet
After VersioningDocument Version 1
document.writeACL = "nobody"
document.writeACL.previous = "user1"
Document Version 2
document.writeACL = "user1"

Specific Request Parameters

(Refer to Common Request Parameters)

Name

Description

Required

Default

Possible Values

apsdb.store

The store name in which you are to save your document.

No

DefaultStore

 

apsdb.update

Specifies whether or not to create a new document if an existing document with the same “apsdb.documentKey” is found

No

 

true
false

apsdb.documentKey

The unique document identifier. It is unique in its store

No

 

 

apsdb.multivalueAppend

Specifies that the given field values will be appended to, instead of replacing, the current field values. Contains a comma separated list of field names to which the values specified will be appended.

No

 

 

[fieldName]

This parameter name in the request is the name of the field to be stored, and its value is the value of the field to be stored.
There can be multiples of this field.

No

 

 

[fieldName].apsdb.fieldType

The type of the data to be stored in the corresponding field.
The field is specified by the first portion of the parameter name.
i.e. This parameter will set the content type of the field whose name is [fieldName]

No

string

string
numeric
date
text
file
geospatial

apsdb.schema

Represents the name of a previously set schema to apply to the document.

No

 

 

apsdb.runAs

It allows the owner to run a service as one of his own users. The possible values are any of the usernames.

No

 

 

[fieldName].apsdb.delete

Parameter used to delete a field or a specific value

No

 

 

apsdb.ftsFields

Comma separated list of fields to index. This parameter can be used for schema-less document only. To specify that a field is searchable for a document that uses a schema, it should be specified in the schema definition itself.

Note that if this parameter is sent with an empty value then nothing will be indexed.

No

 

 

apsdb.revisionNumber

This parameter can only be sent when updating a document. It indicates the revision number of the document that the user expects to be modifying. If the current document has a different revision number than the one specified, then the update will fail and the user will be informed.

No

 

 

apsdb.versioning

Specifies whether this call of SaveDocument should create a new version of the document instead of updating the existing document.

No

false

true
false

apsdb.latestVersion

This parameter can only be sent when versioning a document. It indicates the latest version of the document that the user expects to be modifying. If the latest document has a different version number than the one specified, then the update will fail and the user will be informed.

No

 

numeric

apsdb.authToken

This parameter is used to sign the request with a token that was initially obtained by calling VerifyCredentails API. For more details on signing requests, please refer to the page entitled Authentication.

No

  

The number of characters for the fields of type String is limited to 1024 characters. However, if you wish to add more content, you can use the data type "text". The fields of type text also have a permitted limit of 51200 characters.

Specific Response Elements

(Refer to Common Response Elements)

The following specific "result" element is a child of the common root element "response" and a sibling of the common "metadata" element:

{
	"result":{
		"document":{
			"key":"the key of the document being created; this will be auto-generated if not provided by the user",            
       		"versionNumber":"the version number of the document being created"       
		}
	}
}

Specific Logical Errors

(Refer to Common Logical Error Codes)

Error

Message

Status Code

INVALID_STORE_NAME

Store name is invalid. Please refer to the online documentation for a detailed list of acceptable values

400

DUPLICATE_STORE_NAME

Store already exists, please choose another name

400

STORE_NOT_FOUND

The store was not found

404

CANNOT_MODIFY_DOCUMENT_SCHEMA

Document schema cannot be updated

400

INVALID_DOCUMENT_KEY

 

400

DOCUMENT_KEY_EMPTY

 

400

DUPLICATE_DOCUMENT_KEY

 

400

DOCUMENT_NOT_FOUND

 

404

INVALID_FIELD_VALUE

Incorrect value for fields: [fieldNames]

400

PARAMETER_REQUIRED

 

400

INVALID_FIELD_NAME

 

400

SCHEMA_NOT_FOUND

The schema [schemaName] cannot be found

404

INVALID_PARAMETER_VALUE

Incorrect value for parameter [parameterName].

400

INVALID_PARAMETER_VALUE

Cannot create a new version, versioning is disabled.

400

INVALID_PARAMETER_VALUE

Must create a new version, versioning is forced.

400

CANNOT_MODIFY_DOCUMENT

Revision number sent is different from revision number saved in document

400

INVALID_APPEND_NEW_DOCUMENT

Cannot append values to a new document

400

DUPLICATE_FIELD_VALUE

Field [fieldName] has duplicate values

400

DUPLICATE_FIELD_VALUE

Trying to add duplicate values for field [fieldName]

400

MAX_VALUES_PER_FIELD_EXCEEDED

Field [fieldName] cannot have more than [maximumValue] values

400

FIELD_NOT_MULTIVALUED

Trying to add multiple values to a non-multivalued field [fieldName]: [list of values]

400

DATE_REQUIRED

 

400

INCORRECT_DATE_FORMAT

 

400

ACL_GROUP_NOT_FOUND

 

404

INCONSISTENT_FIELD_TYPE

Field [fieldName] must have the type [fileType] instead of the supplied [suppliedType]

400

INVALID_FIELD_TYPE

Incorrect value [fieldType] for parameter [fieldName]

400

RESTRICTED_FIELD_NAME

 

400

FIELD_NOT_FOUND

Field [fieldName] does not exist.

404

VALUE_NOT_FOUND

Value [filedValue] does not exist.

404

INVALID_FILE_FIELD

Can only add files to the field apsdb_attachments in schemaless documents

400

FIELD_NAME_REQUIRED

 

400

MAX_ATTACHMENTS_SIZE_EXCEEDED

 

400

FIELD_FILE_NOT_DEFINED

 

400

FILE_WITH_SAME_NAME_ALREADY_EXIST

 

400

FILE_ALREADY_EXISTS

The file [fileName] already exists.

400

MAX_FIELDS_EXCEEDED

 

400

INVALID_REQUEST

Incomplete script trigger parameters

400

INVALID_REQUEST

Invalid versioning parameters. apsdb.latestVersion can only be used when creating a new version

400

PERMISSION_DENIED

Script trigger required fields are not in an ACL group

403

PERMISSION_DENIED

Script trigger required fields are not writeable

403

INVALID_PARAMETER

Script trigger handback must be a string value with length <= 1024 bytes

400

INVALID_PARAMETER

Script trigger cronSpec value is not valid

400

INVALID_PARAMETER

Script trigger execAt must be a valid date value

400

CANNOT_CREATE_VERSION

Latest version number sent [versionNumberSent] is different from latest version number of document [latestVersionDocument]

400

Examples

Sample Request

Request URL: http://sandbox.apstrata.com/apsdb/rest/[authenticationkey]/SaveDocument?apsws.time=[timestamp]&apsws.authSig=[signature]


POST parameters:

apsdb.store
apsdb.update=[true|false]
apsdb.documentKey
apsdb.globalDateFormat
[fieldName]=[fieldValue]
[fieldName].apsdb.fieldType=[fieldType]
[fieldName].apsdb.fieldDateFormat=[dateFormat]
apsdb.multivalueAppend=[fieldName1],[fieldName2],...[fieldNameN]


Sample XML Response

Success XML response:

<response xmlns="http://www.apstrata.com/services/schemas/apstrata_database_response.xsd">
     <metadata>
         <requestId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</requestId>
         <status>success</status>       
     </metadata>
     <result>
        <document key="[document_key]" versionNumber="[document_versionNumber]"/>
     </result>
</response>


Failure XML response:

<response xmlns="http://www.apstrata.com/services/schemas/apstrata_database_response.xsd">
     <metadata>
         <requestId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</requestId>
         <status>failure</status>
         <errorCode>[errorCode]</errorCode>
         <errorDetail>[failMsg]</errorDetail>
     </metadata>
</response>


Sample JSON Response

{"response": {
  "metadata": {
    "requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "status": "success"
  },
  "result": {
    "document": {
      "key": "00A84E82A116C2BE1FD57E5399E8F8D4",
      "versionNumber": "1.0"
    }
  }
}}

 

 

 

  • No labels