1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
|
RESTful Web script design
=========================
.. class:: centre
Saulius Gražulis, Algirdas Grybauskas, Andrius Merkys, Antanas Vaitkus
.. class:: centre
$Date: 2020-03-10 08:56:40 -0400 (Tue, 10 Mar 2020) $
.. class:: centre
$Revision: 6304 $
Version history
---------------
+------------+----------------------------+---------+-----------------------------------------------------------+
| Date | Author | Version | Changes |
+============+============================+=========+===========================================================+
| 2020-03-10 | A. Merkys | v0.1.9 | trunk/ |
| | | | |
| | | | Updating the section on backend database limitations as |
| | | | OPTiMaDe filter syntax is adapted and 'action' field |
| | | | is removed. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2020-01-27 | S. Gražulis | v0.1.8 | trunk/ |
| | | | |
| | | | Updating 'DELETE' specification. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2019-12-23 | A. Merkys | v0.1.7 | trunk/ |
| | | | |
| | | | Minor rewordings and fixes. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2019-12-21 | S. Gražulis | v0.1.6 | trunk/ |
| | | | |
| | | | Describing intended REST behaviour in GET, PUT, POST and |
| | | | PATCH requests. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2019-09-20 | A. Merkys | v0.1.5 | trunk/ |
| | | | |
| | | | Describing newly implemented CRUD functionality. |
| | | | Describing input and output data formats. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2019-08-13 | A. Merkys | v0.1.4 | trunk/ |
| | | | |
| | | | Adding a paragraph on name limitations. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2019-07-12 | A. Merkys | v0.1.3 | trunk/ |
| | | | |
| | | | Converting to ReStructuredText, fixing typos. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2018-05-16 | S. Gražulis, A. Grybauskas | v0.1.2 | trunk/ (saulius@varanas.saulius-grazulis.lt) |
| | | | |
| | | | Describing a method to ensure idempotence of PUT and POST |
| | | | POST requests. |
| | | | |
| | | | trunk/ (saulius@varanas.saulius-grazulis.lt) |
| | | | |
| | | | Describing the nested revisions to keep track of the data |
| | | | provenance when data are transferred from another |
| | | | databases with the same or similar schema. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2018-09-13 | S. Gražulis, A. Merkys, | v0.1.1 | trunk/ (saulius@koala.ibt.lt) |
| | A. Vaitkus | | |
| | | | Explaining behaviour when empty JSON is uploaded. |
| | | | |
| | | | trunk/ (saulius@koala.ibt.lt) |
| | | | |
| | | | Further designing the REST interface; updating the |
| | | | project documentation. |
| | | | |
| | | | trunk/ (saulius@varanas.saulius-grazulis.lt) |
| | | | |
| | | | Describing combination of CGI scripts and Web sites from |
| | | | two repositories. |
+------------+----------------------------+---------+-----------------------------------------------------------+
| 2018-05-05 | S. Gražulis | v0.1.0 | Initial revision |
+------------+----------------------------+---------+-----------------------------------------------------------+
Meaning of terms
----------------
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in `RFC 2119`__.
.. __: https://tools.ietf.org/html/rfc2119
Independence requirement
------------------------
The main goal is to achieve independence, simplicity and easy
substitutability of Web scripts that serve representations of various
Web resources. For example, a resource
http://example.net/db/record/12345 might be served by a CGI script
db-record.pl; this script is solely responsible for the logic that
represents records of this particular database, in any supported
representation ((X)HTML, XML, JSON, CIF, etc.). To maintain the SPOT
principle, this script MAY call appropriate libraries that implement
the necessary functionality for generating the representation (for
example, for generating a valid XHTML page given data from a database
record), and these libraries MAY be reused in different scripts serving
different resources, but the relevant decisions on how the resource is
represented MUST be implemented in the top-level script, in this case
in the "db-record.pl".
CLI analogy
-----------
It seems that each of the CGI script could be though as a CLI Unix
command; 'cmd --option=opt-value resource' might be thought as
functionally equivalent to 'https://example.net/cmd/resource?option=opt-value'.
SPOT preservation
-----------------
A script SHOULD call relevant subroutines in a tool libraries for
performing common task and accessing common configurations. This fact,
however, MUST be hidden under the script interface.
Web site vs. Web engine
-----------------------
It seems advisable to separate the CGI scripts and their libraries,
together with configuration examples, into a separate repository; this
repository may or may not contain a simple web site for testing the
scripts. The web sites that provides useful services using these
scripts will be hosted in other repositories, and will use the CGI
script repository either as a public external resource or as a vendor
branch. The web sites will probably run of a specific revision of the
script repository, of a ^/trunk/ if the development is rapid, but for a
production environment they should run from a specific release tag
(released version).
Resource-script mapping
-----------------------
A set of HTTP redirections will be set up to maintain mapping between
resources and scripts.
Form-table duality
------------------
It seems advantageous to generate both the input form (for searches or
selections of the resources) and the (table) representation of the
resource in the same script, to avoid spread of information that must
be kept identical over several scripts.
Object-relation mapping
-----------------------
The underlying resource might be handled using an object in the
implementation language, or as a set of functional calls. It is highly
advisable that objects are used as "smart values", and not as
functional frameworks; if this is the case then the two approaches are
essentially equivalent.
Styles of representations
-------------------------
The generated representations should be as much as possible
style-agnostic. For (X)HTML it means that we most probably will want to
use CSS for defining the visual style.
In any case, we must strive as much as possible to keep content and its
visual representation separate. This cam be achieved in two ways:
1. When using standard (X)HTML or XML and CSS, all visual styles
should go to CSS; this means that HTML elements MUST be properly
marked up: they SHOULD have unique IDs, and MUST have appropriate
class assignments.
2. If CSS are not an option (either not supported by the target
representation at all, like ODT, PDF or LaTeX, or not supported
properly by the target browsers), it is permissible to generate
representation with visual commands embedded (like HTML with
element styles included, or LaTeX with visual formatting included),
but this must be done explicitly by one function that gets data as
one parameter, style list as another parameter, and generates the
representation according to the style given::
$visualHTML = generateVisualHTML( $dataForHtml, $htmlStyle );
In this way, it should be easy to replace representation styles,
and to keep the style consistent.
RESTFUL representation output
-----------------------------
In hierarchical resource representations (such as JSON or XML), foreign
keys of nested subordinate tables pointing to the main record MUST be
omitted.
CRUD functionality and HTTP requests
------------------------------------
HTTP request overview
+++++++++++++++++++++
+-------------+---------------------------------------------+---------------------------------------------------+
| HTTP method | Table | Record |
+=============+=============================================+===================================================+
| GET | Retrieve data of all records in the table, | Retrieve data of a single record |
| | if needed, paginated | |
+-------------+---------------------------------------------+---------------------------------------------------+
| PUT | Insert record(s) into the table; fail on | Insert a record with a specified ID value, |
| | duplicates [#JSON_API_PUT]_ | fail on duplicate [#JSON_API_PUT]_ |
+-------------+---------------------------------------------+---------------------------------------------------+
| PATCH | Update record(s) of the table; fail if | Update a specified record; fail if the record |
| | record(s) to update do(es) not exist | does not exist |
+-------------+---------------------------------------------+---------------------------------------------------+
| DELETE | Fails; dropping tables/deleting their | Deletes a specified record |
| | contents in bulk is allowed after addtional | |
| | confirmation. | |
+-------------+---------------------------------------------+---------------------------------------------------+
| POST | Same as PUT, although SHOULD upsert | Same as PATCH, although SHOULD upsert |
+-------------+---------------------------------------------+---------------------------------------------------+
The support of HTTP POST requests MUST be retained, as HTML forms are
unable to send HTTP requests other than GET and POST. In the current
implementation the action to be taken with HTTP POST is provided via
fields 'Save', 'Update', 'Delete' of multipart/form-data content.
.. [#JSON_API_PUT] Fails for JSON API requests, as HTTP PUT is not
handled by JSON API v1.0
HTTP request behaviour
++++++++++++++++++++++
General requirements for responses in JSON format
-------------------------------------------------
The following keys MUST be returned in the "metadata" object:
- "data_returned" – contains the number of items actually returned
in the query;
- "data_available" – contains the total number of items in the
database that matched the query filter; this is the number of
items that the client can get in principle; this number would be
returned if the page size parameter ("rows") was infinitely large.
GET from a record
-----------------
MUST return a single record (row) of data from a database. SHOULD
return a deep (depth=-1) set of records unless the depth is explicitly
requested.
The following QS parameters MUST be honoured (N is an integer):
- *depth=N* – only related tables up to level N are returned; N=0
indicates that only the requested table's data, and no related table
data MUST be returned. The depth=-1 parameter indicates that
infinite depth must be used, i.e. all related table data MUST be
returned. However, the related data items MAY be limited by the
'rows' number;
- *rows=N* – limit the number of the rows in the related tables to N.
NOTE: currently, "metadata" JSON object is returned for the main table
query, but not for the related tables. It seems very useful if the
"metadata" would be returned also for related tables, in particular its
"data_returned" and "data_available" items; in this way the client
would know that the data from the related tables are incomplete and it
needs to make additional queries to get all data if needed. For this,
the "representation" URI in related table metadata would be very useful.
GET from a table
----------------
MUST return a page with multiple records, up to the 'limit' number of
records. See the 'General requirements for responses in JSON format'_
for the description of the returned metadata.
The following QS parameters MUST be honoured (N is an integer):
- *rows=N* – limit the number of the rows to N;
- *offset=N* – start output with the row number N (zero-based).
The same 'rows' value SHOULD be used for the related tables.
CAVEAT: using the same 'rows' value limits the functionality; we may
wish to have different 'rows' parameters for the main table and for
the related tables. We need to discuss use cases for this more
thoroughly.
PUT to a record
---------------
The PUT request is intended for the insertion of the *new* record. On
the SQL level, this corresponds to the 'INSERT' SQL statement. The
record MAY NOT be inserted into a view, only into a genuine table; if
an insertion into a view is attempted, the request SHOULD return an
error status, 'HTTP 400 Bad Request'. The response payload in JSON
format MUST conform to the response schema and MUST contain the
'error_code' and 'error_message' fields that indicate the nature of the
error ("duplicate unique key '<ID>'").
When PUT request is performed using a *record* URI, the posted data
MUST contain exactly one record; any other number of records in the
posted data is an error; in such case the server database MUST NOT be
changed, and the 'HTTP 400 Bad Request' status code MUST be returned,
with the error message and code identifying the problem. The error
code MUST be distinct from the error code returned on duplicate IDs.
RATIONALE: using PUT request indicates that we need to create a new
record that did not exist before. An existing record with the same ID
is most probably an error, and should be diagnosed appropriately.
NOTE[1]: This specification **obsoletes** the idempotence requirements
of the PUT request in the 'Ensuring idempotence of the write
operations'_ section.
NOTE[2]: This behaviour appears to break the strict idempotence of
the RESTful requests. However, the very nature of the PUT request
makes it necessary to diagnose the duplication of the record. If
duplication of the record is not an error, the client has a choice:
1. Process the 'HTTP 400 Bad Request' status code with the error code
"duplicate unique key" as a regular situation and proceed; the
client MAY assume in this case that the record is present, but it
MUST NOT assume that the data in this record are the one that it
attempted to insert. Most probably, another request to fetch the
data is necessary. The URI to fetch this data MUST be provided in
the response payload;
2. Use POST request if the SQL 'UPSERT' functionality is intended; the
POST request is idempotent in the sense described in the 'POST to a
record'_ section.
If the posted data contain related table records, these records MUST be
inserted in a single transaction; if any of the IDs in the inserted
records exists in the database, if MUST be treated as an error, in the
same way in which the duplicate key of the inserted primary record is
treated.
TODO: consider whether the response payload, the "data" part,
SHOULD/MAY/MUST contain data from the existing record. One
possibility is given below:
The "data" part of the response payload MAY be missing; if it is
present, it MUST contain data from the actual record that is present
in the database, as if it were returned by a GET query to the same
record URI.
RATIONALE: if the insertion fails on duplicate key, the client most
probably will need to know what the actual data is before it can
proceed. Returning "data" with the actual record will save the client
one HTTP request. However, it increases traffic and will most probably
require another SQL request, which complicates the server. Thus, the
server implementer may decide that this feature is too expensive and
not provide it.
Furthermore:
1. After the first insertion, all further requests will be idempotent
and return identical error responses;
2. The PUT request, even if it fails, ensures the invariant "the
record with the requested ID exists in the database";
3. The server might be able to identify that the PUT record is
identical to the one already present in the database and return the
'HTTP 200 Success' code with the existing record payload. However,
this would require another SQL lookup query; it raises questions how
different fields are compared for quality (e.g. floating-point
numbers); and it is not clear what to do if the PUT data contain
less fields than the database table. Thus, it may be prudent and
less error-prone to react to the 'INSERT' failure of the SQL with a
HTTP error code and the corresponding error message.
PUT to a table
--------------
PUT to a table inserts one or several records into the table. The
submitted file MAY contain any number of records, including 0. All
records MUST be new and unique; if a duplicate key is detected (either
present in the database or among the PUT records), the entire PUT
transaction MUST be aborted, the database MAY NOT be changed and the
error status code and message MUST be returned following the
specifications of the 'POST to a record'_ specification.
POST to a record
----------------
The POST request provides the SQL 'UPSERT' functionality; the POST
requests are idempotent in the sense that subsequent identical requests
sent to the server will produce the state of the resource on the server
identical to that after the first request, and produce that same
representation of the resource that the first query produced in the
response (except maybe for different timestamps).
POST to a table
---------------
POST to a table UPSERTs multiple records into the table; the submitted
file MAY contain any number of records, including 0.
If the insertion of any individual record fails, the whole request
MUST fail, and the error code, RESTful error code and message MUST be
returned.
PATCH to a record
-----------------
The PATCH request provides the SQL 'UPDATE' functionality; the PATCH
requests are idempotent in the sense that subsequent identical
requests sent to the server will produce the state of the resource on
the server identical to that after the first request, and produce that
same representation of the resource that the first query produced in
the response (except maybe for different timestamps).
PATCH to a table
----------------
The PATCH to a table modifies several records (including 0); all
records MUST exist.
If the update of any individual record fails for whatever reason, the
whole request MUST fail, and the error code, RESTful error code and
message MUST be returned.
POST'ing to URI with a record identifier
++++++++++++++++++++++++++++++++++++++++
POST'ing to URI with a record identifier MUST update the record, but
NOT the identifiers. Mismatches of provided and existing identifiers
MUST be checked and reported as errors.
A special QS parameter, '&override_ids=1', SHOULD be supported, and
with this QS option, in case the system supports it, the database
identifiers MUST be overwritten by identifiers supplied in the uploaded
JSON file. This is currently the only method to change record
identifiers through the RESTful interface. We should investigate the
possibility to provide extra authorisation for such action.
When a JSON with only UUID identifier of the record is provided, all
Public IDs (such as SOLSA ID) MUST be assigned automatically. Likewise,
when a new Public ID is used to create a new record, UUIDs MUST be
generated automatically.
If no IDs are provided, JSON MUST be posted to the URI with the UUID or
PublicID (i.e. SOLSA ID), and this ID from the URI will be assigned to
the submitted JSON data.
When inserting POST'ed data, internal primary keys ('id' columns) MUST
be ignored.
Ensuring idempotence of the write operations
--------------------------------------------
When the same data are PUT, POSTed or otherwise submitted to the
RESTFul interface, the underlying implementation MUST ensure that
submitting identical data for the second time does not change the
database state. The implementation MUST ensure this when submitted file
is bit-wise identical; it MAY apply some canonical transformation (e.g.
removing insignificant spaces and newlines, forcing identical quotes,
etc.) on the submitted file.
A possible implementation using SQL database is as follows. While
comparing (diff'ing) the submitted file contents against the existing
database content might be used, it will most probably be too
inefficient. Thus, an implementation that uses cryptographic checksums
for detecting identical data might be used. The implementation would
compute, after receiving the uploaded data file, and possibly after
application of some canonical transformations, checksum (SHA1 or
analogous) of the incoming file. The checksums of the inserted files,
along with their contents and other metadata (filename, upload date,
database revision number after data insertion), would be stored in a
separate database table. Before insertion of the data, a check is made
whether the newly calculated checksum is already present in a data
table. If yes, the actual insertion is not performed, thus preventing a
spurious new revision of the database to be generated, and the the same
answer as after the original insertion (e.g. the revision contents of
the insert revision) is returned. Otherwise, transaction is started, a
new database revision is recorded and the newly calculated cheksum and
file data are inserted into the checksum table, after which all regular
insertions (including the revision number) is performed. The the
transaction is committed or rolled back as usual. If transactions are
not used, the checksum database table MUST contain the 'committed' bit
which is set to 0 (false) before the insertions are started and set to
'1' (true, meaning that the file is committed) when also insertions are
performed successfully.
Return of the RESTful post queries
----------------------------------
For databases that use revision tables, a contents of the newly created
revision record MAY be returned. If a request is repeated and detected
as such, then the contents of the revision record when the data where
actually inserted. The response returned on duplicate PUT or GET query
MUST be the same as the response of the first query (when the actual
insertion or update actually took place), except that the application
MAY insert additional audit fields as the current query time or query
ID.
Revision chaining upon data transfer
------------------------------------
When data are transferred from one database (e.g. an on-field database)
to another (e.g. a centralised archive repository), a data provenance
should be kept, keeping information of the original insertion revision
as well as the current transfer revision, and possibly all the
intermediate revisions.
The revision table should thus have a 'previous_revision_id' column.
This column MUST be NULL for the newly inserted revisions. For the data
transferred from other databases, it will contain a reference to the a
previous revision (or a revision chain) that came with the data (e.g.
in the JSON or XML file). The old revisions will be inserted as
ordinary data into the revision table.
Input and output data formats
-----------------------------
A RESTful database is capable of supporting input and output of
virtually infinite set of data formats. The principle requirement for
support of a data format is an unambiguous mapping to an underlying
relational data model. Tabular data formats (spreadsheets and the like;
CSV, ODS, XLS, to name a few) are straightforward to map, whereas
document-oriented (like XML) or loosely structured (like JSON) are
more difficult to support.
A RESTful method to submit input in a specific data format in HTTP
PUT/POST/PATCH is by sending its contents to a backed with
'Content-Type' HTTP header set using Internet Media Type conventions.
The accepting script MUST check the supplied value of 'Content-Type'
HTTP to determine whether the supplied input can be handled. If unknown,
such format MUST be reported via either 400 Bad Request or 501 Not
Implemented HTTP statuses. The default input format SHOULD be
'multipart/form-data'.
Output format MAY be specified by the client using one of the following
methods: 'format' QS parameter or 'Accept' HTTP header. Again,
unsupported formats MUST be reported. The default output format MUST be
HTML.
Error handling
--------------
In no case SHOULD a script crash, cause "internal server error", or
return a blank page without any error code.
Errors should cause:
1. An appropriate human- and machine- readable response;
2. A HTTP error code, so that the client software knows how to behave.
In order to prevent attempts to break into the site server by guessing
passwords or extracting information via the error messages, the
response MAY conceal the exact cause of the error from the client; in
that case, however, it MUST mention the the exact error message will be
presented in the server logs, and MUST log full error message into the
log. For instance:
* HTML response:
* "We regret but the server can not grant you access to modify the
record "db/12345" on this server. Please try to log in (once more).
The exact cause of the denial is recorded in the server logs;
please contact admin@example.net for assistance."
* Log message:
* "update.pl: ERROR, permission denied for user 'eve' - password
incorrect."
or:
* "update.pl: ERROR, permission denied for user 'adam' - no such user."
Configuration
-------------
Unfortunately but inevitably Web software requires configuration,
authentication and authorisation.
Configuration should proceed automatically as much as possible. If a
script does not find a database in a specified location, but can write
a file in that location, and the database is a file (a typical
situation when the script is started for the first time after a
successful installation), then the script SHOULD create the database
using default schema. If a script needs a configuration file, but can
not find this file, it should create a config file with as much content
as possible from the defaults or from a configuration template. If a
database access needs to be provided to a database server, a script
should inform the user how to set up such access.
Security
--------
One should ensure that configuration files, especially ones containing
passwords, are not readable by the outside users. This MUST be actively
checked during the operation. Default passwords MUST NOT be used;
instead, first time passwords MUST be generated upon installation from
reliable random sources and recorded in a place which is only
accessible for the system administrator. If GPG or X509 certificates
are available, the password MAY be encrypted using the public keys.
Possible secure configuration methods:
1. Upon the first start, the server detects missing configuration
files and/or not writable directories, and presents a page with
detailed step-by-step instructions on how to set up the server,
having access to the server command line;
2. Upon the first start, server asks the user to fill in forms for
server configuration, generates the configuration files and makes
them read-only. To make sure that only legitimate user can
configure the service, such configuration forms MUST be only
presented on localhost, or MUST require an action to be performed
on a server (e.g. a special file must be created with a random
string that was presented to the user; this random string must be
valid for a limited time)
Limitations for the backend databases
-------------------------------------
Due to the interplay of various namespace choices some limitations for the
supported backend databases exist:
* Table and column names MUST consist only of alphanumeric symbols and
an underscore symbol. Names MUST NOT start with a digit. Uppercase
letters are allowed in names only if table and column names are
case-insensitive. That is, all tables and columns MUST be queryable
using all-lowercase names. These limitations arise from the usage of
OPTiMaDe filter syntax in RestfulDB.
* As table columns and composite foreign keys are placed in the same
namespace, there MUST NOT be a column and a composite foreign key
with the same name in the same table. If a composite foreign key is
unnamed, then the name of the parent table is used.
|