Dienstag, 1. September 2015

REST-Services - völlig ohne Schema - mit "SODA": So geht's.

Ich freue mich, dass heutige Blog-Posting von Rainer Willems vorstellen zu können. Rainer zeigt, wie man SODA (Simple Oracle Document Access) einrichtet und damit REST-Services in der Oracle-Datenbank - völlig ohne Schema bereitstellen kann. Jedes beliebige JSON wird entgegengenommen. Ihr könnt Rainer auf Twitter folgen: @josifabr.

Als Abwechslung zur skriptbasierten Vorgehensweise, die ich in den letzten Blog-Postings verwendet habe, seht Ihr hier die Vorgehensweise mit dem SQL Developer. Viel Spaß beim Lesen und Ausprobieren.



Heute wollen wir uns mit SODA beschäftigen. Hierbei handelt es sich nicht um eine dem aktuellen Wetter angepasste Erfrischung, sondern um Simple Oracle Document Access. Carsten hat im Blog schon gezeigt, wie einfach eine bestehende Tabelle mit ORDS REST-fähig gemacht werden kann oder wie ein solcher Service mit PL/SQL aufgebaut werden kann.

Dies erfüllt aber noch nicht die Anforderungen von Entwicklern, vollständig flexibel - also ohne vorgegebenes Schema - arbeiten so können. NoSQL-Datenbanken preisen dies als Vorteil an. Auch Oracle wartet hier mit einer NoSQL-Datenbank auf. Habe ich aber ohnehin Oracle 12c im Einsatz, wäre es doch viel einfacher, diese eine (unter vielen, vielen anderen) Anforderung mit der gleichen Datenbank abzudecken. Und genau hier kommt SODA ins Spiel. SODA bietet die Möglichkeit die Datenbank als flexiblen schemaless Document-Store zu verwenden: Oracle DB als NoSQL JSON document store

Wir betrachten betrachten im Folgenden nun SODA for REST, ebenfalls verfügbar ist SODA for Java.

Voraussetzung auf Datenbankseite ist das Release 12.1.0.2 und der Patch 20885778 Ist dieser installiert und der ORDS wie beschrieben installiert, kann es losgehen; oder besser gesagt, sind wir eigentlich schon fertig.

Der Vollständigkeit halber hier die Beschreibung der Installation des ORDS mit dem SQL Developer. Unter Tools-REST data Services findet man den Punkt Install

Wir wählen entweder den in der aktuellen SQL Developer Version mitkommenden ORDS oder einen anderen, ggf. aktuelleren (Im momentan aktuellen SQL Developer 4.1.0.19 befindet sich auch der momentan aktuellste ORDS). Dazu wählen wir eine Lokation für die Konfigurationsfiles:


Wir verbinden uns mit der Datenbank und legen einen Public User an, welcher vergleicbar mit dem APEX_PUBLIC_USER ist, nur eben für die REST-Services.


Dies muss als sys geschehen, da in der Datenbank das Metadaten-Repository für die Services angelegt wird (Schema ORDS_METADATA)


Wir legen die Tablespaces fest.


und ignorieren in den kommenden beiden Steps die Einstellungen zum PL/SQL Gateway bzw. APEX.



Wir möchten die Services zum Testen Standalone laufen lassen und definieren den HTTP Port.



Achtung. Wer hier in Konflikt mit einem bereits verwendeten Port kommt und die Installation dann ein weiteres mal versuchen möchte, muss erst die Konfigurationsdatei im Filesystem löschen, da sonst weiterhin die beim ersten Versuch angegebene Port-Nummer verwendet wird.

Für Entwicklungszwecke definieren wir noch einen Admin- und einen Entwicklungsuser (keine Datenbankuser).




Ist der ORDS dann gestartet, sollten wir auch die dementsprechende Anzeige im Log bekommen.



Läuft der ORDS dann, erkennt man das auch an einem roten Quadrat in der Menuleiste des SQL Developer. Clickt man dieses an, wird der ORDS beendet ...


... und die Installation kann unter Tools - REST Data Services - Run wieder gestartet werden (wobei man wieder ein paar Fragen beantworten muss)





Jetzt braucht man nur noch das gewünschte Datenbankschema (das was nachher herauskommt ist trotzdem "schema-less"!) "REST-fähig" machen. Das kann man einfach über das Kontextmenu in den Verbindungen machen.


Der Schemaalias wird nachher in den URLs der REST Services verwendet.



Letztendlich wird hier die Prozedur ORDS.ENABLE_SCHEMA ausgeführt:
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN

    ORDS.ENABLE_SCHEMA(p_enabled => TRUE,
                       p_schema => 'SCOTT',
                       p_url_mapping_type => 'BASE_PATH',
                       p_url_mapping_pattern => 'scott',
                       p_auto_rest_auth => FALSE);
    
    commit;
END;

FERTIG !!!! Die Datenbank kann nun via REST als JSON Document Store verwendet werden. Zum Testen deaktivieren wir nur noch die Security (als User scott in diesem Fall hier). Aber bitte nur zum Testen:
begin
     ords.delete_privilege_mapping('oracle.soda.privilege.developer','/soda/*');
end;
 /

Ich verwende übrigens gerne den Postman, eine Extension für den Chrome-Browser, um REST-Zugriffe zu testen.

Mittels eines GET auf http://mymachine:port/myords/myschema/soda/latest/ kann man sich nun anschauen, welche Collections in unserem Schema vorhanden sind:



Es sind natürlich noch keine da. Eine neue Collection läßt sich mittels eines PUT unter Angabe des gewünschten Collection-Namens erzeugen



Diese erscheint direkt als Datenbank-Tabelle im dementsprechenden Schema.


Neben der ID und dem JSON Dokument als solchem werden noch die Version (von SODA), das Erstelldatum und die letzte Modifikation in der Tabelle gepflegt.



Frage ich nun nochmal alle Collections ab, erhalte ich meine gerade angelegte Collection:
{
  "items": [
    {
      "name": "mycollection",
      "properties": {
        "schemaName": "SCOTT",
        "tableName": "mycollection",
        "keyColumn": {
          "name": "ID",
          "sqlType": "VARCHAR2",
          "maxLength": 255,
          "assignmentMethod": "UUID"
        },
        "contentColumn": {
          "name": "JSON_DOCUMENT",
          "sqlType": "BLOB",
          "compress": "NONE",
          "cache": true,
          "encrypt": "NONE",
          "validation": "STANDARD"
        },
        "versionColumn": {
          "name": "VERSION",
          "type": "String",
          "method": "SHA256"
        },
        "lastModifiedColumn": {
          "name": "LAST_MODIFIED"
        },
        "creationTimeColumn": {
          "name": "CREATED_ON"
        },
        "readOnly": false
      },
      "links": [
        {
          "rel": "canonical",
          "href": "http://localhost:8080/ords/scott/soda/latest/mycollection"
        }
      ]
    }
  ],
  "more": false
}

Die Dokumente werden hier letztendlich in einem BLOB abgelegt. Dieses BLOB wird mittels eines Check-Constraints mit der Bedingung
      "JSON_DOCUMENT" is json format json
überwacht, damit dort auch nur JSON Dokumente abgelegt werden können. Spätestens hier wird klar, weshalb wir für SODA 12.1.0.2 benötigen, da die JSON-Funktionalität hier erst eingeführt wurde.

Mit einem einfachen POST kann man nun ein JSON Dokument in die Collection schieben ...


... und bekommt in der Antwort auch die ID zurückgeliefert, die dieses Dokument bekommen hat.


Fragt man nun die Collection ab (also ein GET auf http://localhost:8080/ords/scott/soda/latest/mycollection), bekommt man eine Aufstellung der Daten:
{
  "items": [
    {
      "id": "CBD1D6D35A66419390F4DB73F0B842E7",
      "etag": "5B4B2052A0927083D1C835CAD4DC59BA4AA6D6C8F99264775EEABE9E6F9BCE49",
      "lastModified": "2015-07-01T15:58:37.925000Z",
      "created": "2015-07-01T15:58:37.925000Z",
      "links": [
        {
          "rel": "self",
          "href": "http://localhost:8080/ords/scott/soda/latest/mycollection/CBD1D6D35A66419390F4DB73F0B842E7"
        }
      ],
      "value": {
        "first": "Guenther",
        "last": "Stuerner",
        "address": {
          "Street": "Liebknechtstrasse",
          "City": "Stuttgart",
          "PLZ": "70565"
        }
      }
    },
    {
      "id": "E4D885A4B3F04FBC8457482E1DA0C01E",
      "etag": "511BAD96CC7C4037E8B20E5E65EBC29E7A034A273684AC2EA9029157C4EF1812",
      "lastModified": "2015-07-01T15:58:20.779000Z",
      "created": "2015-07-01T15:58:20.779000Z",
      "links": [
        {
          "rel": "self",
          "href": "http://localhost:8080/ords/scott/soda/latest/mycollection/E4D885A4B3F04FBC8457482E1DA0C01E"
        }
      ],
      "value": {
        "first": "Rainer",
        "last": "Willems",
        "address": {
          "Street": "Robert-Bosch-Strasse",
          "City": "Dreieich",
          "PLZ": "63303"
        }
      }
    },
    {
      "id": "27200D52F15C4A8F82868C353112E350",
      "etag": "51948BD2C13AE6A0962304FCC325743D1A5F976D687D0A03BFB732D2436CF316",
      "lastModified": "2015-07-01T15:58:29.077000Z",
      "created": "2015-07-01T15:58:29.077000Z",
      "links": [
        {
          "rel": "self",
          "href": "http://localhost:8080/ords/scott/soda/latest/mycollection/27200D52F15C4A8F82868C353112E350"
        }
      ],
      "value": {
        "first": "Paul",
        "last": "Wehner",
        "address": {
          "Street": "Robert-Bosch-Strasse",
          "City": "Dreieich",
          "PLZ": "63303"
        }
      }
    }
  ],
  "hasMore": false,
  "count": 3,
  "offset": 0,
  "limit": 100,
  "totalResults": 3,
  "links": []
}
Hierbei lassen sich natürlich Parameter mitgeben, um die Ausgabe zu Filtern (darüber werden wir noch berichten). Für die Abfrage eines einzelnen JSON-Dokumentes hänge ich einfach die ID an das GET an.



Folgende Befehle sind nun also möglich
PUT    - http://localhost:8080/ords/scott/soda/latest/mycollection     Anlegen einer Collection
GET    - http://localhost:8080/ords/scott/soda/latest/                 Anzeige aller Collections
GET    - http://localhost:8080/ords/scott/soda/latest/mycollection     Anzeige des Inhaltes einer Collection
GET    - http://localhost:8080/ords/scott/soda/latest/mycollection/id  Anzeige eines JSON-Dokumentes
POST   - http://localhost:8080/ords/scott/soda/latest/mycollection     Übergabe und Anlage eines Dokumentes
DELETE - http://localhost:8080/ords/scott/soda/latest/mycollection/id  Löschen eines Dokumentes
  ... besser nicht verwechseln mit
DELETE - http://localhost:8080/ords/scott/soda/latest/mycollection     ... denn dann ist die Collection weg

Weitere Möglichkeiten wie Bulk-Insert und Delete sowie verfügbare Actions sind in der Dokumentation ausführlich beschrieben.
Der riesige Vorteil, den wir nun erhalten, findet sich in der Datenbank. Da diese per SQL mit JSON-Dokumenten umgehen kann, sind der Suche in diesen Dokumenten oder der Verknüpfung dieser mit relationalen Inhalten keine Grenzen gesetzt. Und das mit ein paar einfachen Schritten. Wer will da noch eine zusätzliche Datenbank installieren, verwalten, sichern, ....

Noch ein kleiner Hinweis, falls die Restservices wieder entfernt werden sollen. Da die Metaobjekte aus der Datenbank wieder entfernt werden muss man sich mit SYSDBA Privilegien anmelden. Der Zusatz "as sysdba" wird aber aktuell (SQL Developer 4.1.0.19) im Gegensatz zur Installation vom Tool nicht automatisch angehängt, sondern muss manuel eingetragen werden.


Keine Kommentare:

Kommentar veröffentlichen