|
|
(39 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
− | __NOTOC__== DBRS Design ==
| + | ignore |
− | The DBRS utility starts by reading some initial configuration information:
| + | |
− | <source lang="text" enclose="div">
| + | |
− | prompt > DBRSBuilder [-builderFile {path to dbrsbuilder.properties}] -stageDir {path to stageDir}
| + | |
− | (if command-line arg -builderFile not present, default to look in current working directory)
| + | |
− | prompt > DBRSBuilder running, connected to port 8884 ... Press <Return> to finish
| + | |
− | | + | |
− | dbrsbuilder.properties:
| + | |
− | | + | |
− | # builder properties
| + | |
− | builder.port=8884
| + | |
− | #builder.mode=production
| + | |
− | builder.mode=test
| + | |
− | builder.test.port=8885
| + | |
− | | + | |
− | # project properties
| + | |
− | project.name=myproject
| + | |
− | project.entities=employee, other entities ...
| + | |
− | | + | |
− | # database properties
| + | |
− | db.driver=com.mysql.jdbc.Driver
| + | |
− | db.url=jdbc:mysql://localhost:3306/db
| + | |
− | db.user=user
| + | |
− | db.pwd=password
| + | |
− | db.platform=org.eclipse.persistence.platform.database.MySQLPlatform
| + | |
− | logging.level=info
| + | |
− | </source>
| + | |
− | If the table name does not match the entity name, the user may specify an alias:
| + | |
− | <source lang="text" enclose="div">
| + | |
− | # project properties
| + | |
− | alias.employee.tablename=EMP
| + | |
− | </source>
| + | |
− | The DBRS utility will login in to the database using the given database credentials and 'scrape' the meta-data for the <tt>employee</tt> table: column names and datatypes, PKs, foreign-key relationships, etc. If the built-in pluralization does not generate acceptible URIs, the user can add an alias for that as well - e.g. if the entity is <i>person</i>, the plural should be <i>people</i>, not <i>persons</i>:
| + | |
− | <source lang="text" enclose="div">
| + | |
− | # project properties
| + | |
− | alias.person.plural=people
| + | |
− | </source>
| + | |
− | | + | |
− | The DBRS utility operates at two levels:
| + | |
− | # it builds <b><i>RESTful</i></b> applications (see [[#RESTful_URI_Design_Principles|below]] for more details on <b><i>RESTful</i></b> design principles); and
| + | |
− | # it is <u>itself</u> a RESTful application that listens for messages that manipulates 'meta-resources', the in-memory representation of the meta-data for all entities in the project . This in-memory model is based on EclipseLink JAXB's OXM meta-data and EclipseLink JPA's ORM meta-data (<code>javax.persistence.metamodel</code> API):<br/>[[Image:JPA2Metamodel.png]]<br/>
| + | |
− | | + | |
− | ===== DBRS URI Design =====
| + | |
− | Of primary importance is the design of the URIs for each resource (entity):
| + | |
− | {|{{BMTableStyle}}
| + | |
− | |-{{BMTHStyle}}
| + | |
− | ! URI
| + | |
− | ! Operation
| + | |
− | ! Result
| + | |
− | |-
| + | |
− | | <nowiki>/myproject/entities/employees/</nowiki>
| + | |
− | |
| + | |
− | {|
| + | |
− | |GET
| + | |
− | |-
| + | |
− | |PUT
| + | |
− | |-
| + | |
− | |POST
| + | |
− | |-
| + | |
− | |DELETE
| + | |
− | |}
| + | |
− | |
| + | |
− | {|
| + | |
− | |retrieve list of employees (200 OK)
| + | |
− | |-
| + | |
− | |replace list of employees (201 Created)
| + | |
− | |-
| + | |
− | |add a new employee (201 Created)
| + | |
− | |-
| + | |
− | |unused (400 Bad Request)
| + | |
− | |}
| + | |
− | |-
| + | |
− | | <nowiki>/myproject/entities/employees/count</nowiki>
| + | |
− | | GET (with search modifier)
| + | |
− | |retrieve a count of the list of employees (200 OK)
| + | |
− | |-
| + | |
− | | <nowiki>/myproject/entities/employees/?pgNum=0&pgSize=40</nowiki>
| + | |
− | | GET (with query parameters)
| + | |
− | |retrieve the first group of 40 employees (200 OK) <br/>
| + | |
− | Message body should include the following additional information:
| + | |
− | * pageNum: reflects the pgNum query parameter (or 0 for the default first page)
| + | |
− | * pageSize: reflects the pgSz query parameter (or the default page size)
| + | |
− | * itemsInPage: reflects the total number of employees in the current page
| + | |
− | * totalItems: reflects the total number of employees
| + | |
− | |-
| + | |
− | | <nowiki>/myproject/entities/employee/{id}</nowiki>
| + | |
− | |
| + | |
− | {|
| + | |
− | |GET
| + | |
− | |-
| + | |
− | |PUT
| + | |
− | |-
| + | |
− | |POST
| + | |
− | |-
| + | |
− | |DELETE
| + | |
− | |}
| + | |
− | |
| + | |
− | {|
| + | |
− | |retrieve employee details (200 OK | 404 Not Found)
| + | |
− | |-
| + | |
− | |update employee details (201 Created | 404 Not Found)
| + | |
− | |-
| + | |
− | |add a new employee (201 Created)
| + | |
− | |-
| + | |
− | |remove employee (204 No Content | 404 Not Found)
| + | |
− | |}
| + | |
− | |}
| + | |
− | | + | |
− | ===== DBRS meta-resources URI Design =====
| + | |
− | In addition, the URIs for an entity's <i>meta-resources</i>: <br/>Note: all properties in <code>dbrsbuilder.properties</code> can be accessed as resources
| + | |
− | {|{{BMTableStyle}}
| + | |
− | |-{{BMTHStyle}}
| + | |
− | ! URI
| + | |
− | ! Operation
| + | |
− | ! Result
| + | |
− | |-
| + | |
− | |<nowiki>/dbrsbuilder/project/name</nowiki>
| + | |
− | |GET
| + | |
− | |retrieve the name of the current project (200 OK)
| + | |
− | |-
| + | |
− | |<nowiki>/dbrsbuilder/db/user</nowiki>
| + | |
− | |PUT
| + | |
− | |update the <tt>db.user</tt> property (201 Created)
| + | |
− | |-
| + | |
− | |<nowiki>/dbrsbuilder/alias/employee/plural</nowiki>
| + | |
− | |PUT
| + | |
− | |update the <tt>alias.employee.plural</tt> property (201 Created)
| + | |
− | |-
| + | |
− | |<nowiki>/dbrsbuilder/meta/model</nowiki>
| + | |
− | |GET
| + | |
− | |retrieve the meta-model for the current project (200 OK)
| + | |
− | |-
| + | |
− | |}
| + | |
− | | + | |
− | ===== RESTful URI Design Principles =====
| + | |
− | The term REST - <b>RE</b>presentational <b>S</b>tate <b>T</b>ransfer - was introduced and defined in 2000 by [http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm Roy Fielding in his doctoral dissertation] (Fielding is one of the principal authors of the HTTP v1.1 spec). Conforming to Fielding's architecture is referred to as being <b><i>RESTful</i></b>. A RESTful web service (also called a RESTful [http://en.wikipedia.org/wiki/Web_API web API]) is implemented using HTTP and the principles of REST, with emphasis on the following aspects:
| + | |
− | # definition of URIs for <b>all</b> resources exposed by the web service: e.g. <nowiki>/myproject/entities/</nowiki><b><i>car</i></b>
| + | |
− | # use of Internet media types for on-the-wire representation. This is often JSON or XML, but can be any valid Internet media type.
| + | |
− | # use of the HTTP v1.1 operations: POST, GET, PUT, and DELETE - [http://en.wikipedia.org/wiki/Create%2C_read%2C_update_and_delete analogous to the database semantics of CRUD: <b>C</b>reate, <b>R</b>etrieve, <b>U</b>pdate and <b>D</b>elete].
| + | |
− | # use of hyperlinks to interact with/navigate to resources.
| + | |
− | | + | |
− | A URI is structured as follows: <tt>domainname/[contextual key(s)]/[resource name]/?[query args and modifiers]</tt> and should follow the following Design Principles:
| + | |
− | # A URI must represent a unique object, permanently: if it becomes necessary to relocate a resource, use the response code <tt>HTTP 301 (redirect)</tt> so that the client can find where the resource has been moved to.
| + | |
− | # should be succinct and easy-to-understand: <tt>/some/resource/about</tt> is preferred over <tt>/some/resource/about-acme-corp</tt>.
| + | |
− | # A URI's structure must be consistent: once the strategy is chosen, follow it. As in 1), if the strategy changes, return <tt>HTTP 301</tt> so that users familiar with resources under the previous structure can find them under the new structure.
| + | |
− | # A URI must follow <b>POLA</b> - [http://http://en.wikipedia.org/wiki/Principle_of_least_astonishment|<b>P</b>rinciple <b>O</b>f <b>L</b>east <b>A</b>stonishment]: URIs should be structured so that they are intelligibly 'hackable'. For example, if the URI <tt>/events/2010/01</tt> represents the events for January 2010, then it follows that:
| + | |
− | #: <tt>/events/2009/01</tt> - represents events for January 2009
| + | |
− | #: <tt>/events/2010</tt> - represents events for the entire year of 2010
| + | |
− | #: <tt>/events/2010/01/21</tt> - represents events for January 21st, 2010
| + | |
− | # URIs should be composed of keywords that are important to the context of the resource. Typical contextual keys describe:
| + | |
− | #: a resource's type
| + | |
− | #: a resource's category - or parent category
| + | |
− | #: key resource data/attributes (i.e. the date posted)<div style="line-height:125%"><br/></div>Typically, a URI specifies a categorization that moves from general to specific, e.g. a descending hierarchy like year -> month -> day
| + | |
− | # A URI should not contain any markers that would allow someone to infer (correctly or otherwise!) what sort of underlying implementation technology is being used. Suffixes such as <tt>.php</tt> or <tt>.aspx</tt> should not be used.
| + | |
− | # A URI should be lowercase up to the [resource name] - query args and modifiers can be mixed case. In addition, query args and modifiers change only the <b><i>view</i></b> presented for a resource, <b>never</b> its underlying representation. For example a chart service may show some rows from a database; a query modifier may indicate that the chart should be rendered as a PDF file instead of a PNG image - the presence of the query modifier should in no way alter the information contained in the rows.
| + | |
− | # A URI that refers to a list of resources should use plural nouns; a URI that refers to a single resource should use singular nouns:
| + | |
− | #:: GET <tt><nowiki>/myproject/entities/employees</nowiki></tt> - returns a list of employees
| + | |
− | #:: GET <tt><nowiki>/myproject/entities/employee/1</nowiki></tt> - returns the first employee
| + | |
− | # Pagination of returned lists of resources is supposed to be managed via HTTP header attributes called HTTP Ranges. Unfortunately, this requires returning response code <tt>HTTP 206 (Partial Content)</tt> which is not universally accepted by clients. Thus pagination is typically accomplished by appending query modifiers to indicate page number and size:
| + | |
− | #:: GET <tt><nowiki>/myproject/entities/employees/?pgNum=0&pgSize=40</nowiki></tt> - returns the first group of 40 employees
| + | |
− | #:: GET <tt><nowiki>/myproject/entities/employees/?pgNum=1&pgSize=20</nowiki></tt> - returns the next group of 20 employees
| + | |
− | :To protect the server from 'greedy' clients that try to query the entire database, use the response code <tt>HTTP 413 (Request Entity Too Large)</tt> if necessary. The Entity tag (ETag) header, when used with <tt>Last-Modified/If-None-Modified/If-Modified-Since</tt> headers, is essential for handling the <i>[http://www.w3.org/1999/04/Editing lost update problem]</i> when editing resources selected from (partial) paginated lists.
| + | |