[{"content":" Tredje artikkel om Oracle REST Data Services omhandler hvordan et API beskyttes med OAuth 2 og OIDC.\nOAuth 2 og OIDC for Oracle REST Data Services Første del i denne serien introduserte Oracle REST Data Services (ORDS) og viste hvordan man lager et REST API på tabeller og views med noen få klikk i SQL Developer.\nI Andre del ble ORDS API brukt til å definere et mer avansert REST API med litt mer kode.\nI denne delen ser vi på sikkerhet, det vil si hvordan du beskytter et API med standard protokoller som OAuth 2 og OpenID Connect (OIDC). Detaljer rundt OAuth 2 og OIDC er det ikke plass til her, men for de som vil lære seg det inngående er det enkelt å se fra dokumentasjon hvordan ORDS støtter standarden. Dokumentasjon og enkel eksperimentering med ORDS er et godt utgangspunkt for å lære seg hvordan disse tingene henger sammen før man studerer dette i dybden.\nEt API som tillater noe mer enn å hente ut åpne data må typisk beskyttes med autentisering og autorisering. Dette kan selvsagt gjøres på mange måter, men her vises hvordan det gjøres med funksjonalitet i ORDS.\nDet er hovedsaklig to måter å gjøre det på med ORDS:\nOpprette klienter og roller lokalt med ORDS Bruke en ekstern leverandør som har ansvar for autentisering og utstedelse av token Opprette klienter lokalt Fordelen med dette er at det er enkelt og du har full kontroll selv. For en som er ny til OAuth er dette en god måte å komme i gang på, siden man har full kontroll og slipper å involvere andre i eventuell feilsøking. Ulempen er at du oppretter enda en ID-løsning i stedet for å overlate det til andre, dermed må klientene forholde seg til en ekstra bruker-konto i stedet for en sentralt styrt (tjeneste)bruker. En løsning med få brukere eller for å komme raskt i gang er dette et greit alternativt. (Og er den eksterne ID-leverandøren en sort boks langt borte er dette et fristende alternativ.)\nI eksempel her brukes endepunkt /ords/admin/timereg/prosjekt/ opprettet i forrige artikkel . I følgende kodebit opprettes en rolle Prosjektadministrator og et privilegium timereg.prosjekt for endepunkt timereg/prosjekt/:\nDECLARE l_priv_roles owa.vc_arr; l_priv_patterns owa.vc_arr; l_priv_modules owa.vc_arr; BEGIN l_priv_roles(1) := \u0026#39;Prosjektadministrator\u0026#39;; l_priv_patterns(1) := \u0026#39;/timereg/prosjekt/\u0026#39;; -- Del av URL etter admin l_priv_modules(1) := \u0026#39;timereg\u0026#39;; ords.create_role(l_priv_roles(1)); ORDS.DEFINE_PRIVILEGE( p_privilege_name =\u0026gt; \u0026#39;timereg.prosjekt\u0026#39;, p_roles =\u0026gt; l_priv_roles, p_patterns =\u0026gt; l_priv_patterns, p_label =\u0026gt; \u0026#39;Prosjektadministrator\u0026#39;, p_description =\u0026gt; \u0026#39;Privilegium for administrasjon av prosjekter\u0026#39;, p_comments =\u0026gt; \u0026#39;En berikende kommentar\u0026#39;); commit; end; / Privilegier og koblinger hentes ut slik:\nselect * from user_ords_privileges ; select * from user_ords_privilege_mappings; Referansedokumentasjon til ORDS-pakken er vist i kap 4 i *Developer\u0026rsquo;s Guide .\nEn ny test på samme url vil nå returnere 401 Unauthorized fordi det ikke finnes en bruker/klient med rollen. En lokal bruker i ORDS kan opprettes slik:\nbin/ords --config ordsconfig config user add prosjekt_admin \u0026#34;Prosjektadministrator\u0026#34; Brukernavn er altså prosjekt_admin og den får rollen Prosjektadministrator. ORDS må også restartes etter at bruker er lagt til. Eksempel med curl og basic authentication:\ncurl --user prosjekt_admin:PR2024 rio:8080/ords/admin/timereg/prosjekt/ Forsøker man i nettleser med url som vist får man samme feil med 401, men man kan logge inn ved å klikke på Sign in som vist her:\nLokal bruker som vist over er bare anvendelig til utvikling lokalt og i små systemer.\nPakken OAUTH brukes til å opprette OAuth-klienter. Her lages det en som får samme privilegium og rolle som opprettet over:\nBEGIN oauth.create_client( p_name =\u0026gt; \u0026#39;Timereg Administrator\u0026#39;, p_grant_type =\u0026gt; \u0026#39;client_credentials\u0026#39;, p_privilege_names =\u0026gt; \u0026#39;timereg.prosjekt\u0026#39;, p_support_email =\u0026gt; \u0026#39;support@example.com\u0026#39; ); oauth.grant_client_role( p_client_name =\u0026gt; \u0026#39;Timereg Administrator\u0026#39;, p_role_name =\u0026gt; \u0026#39;Prosjektadministrator\u0026#39; ); COMMIT; END; / Eksisterende klienter kan listes ut med:\nselect * from user_ords_clients; For å få ut kun name, client_id og client_secret:\nSELECT name, client_id, client_secret FROM user_ords_clients; Man trenger selvsagt ikke restarte ORDS etter at en client er opprettet slik (det gjelder kun lokale brukere som vist over.)\nEt opaque access token kan hentes ut med:\ncurl -i -k --user xZwkGJnZTZA2PkDlN_36FA..:D4PinTMYJEGugwD7Zqu_Dg.. \\ --data \u0026#34;grant_type=client_credentials\u0026#34; rio:8080/ords/admin/oauth/token Her er hhv CLIENT_ID og CLIENT_SECRET fra USER_ORDS_CLIENTS brukt i autentisering. ORDS returnerte her:\nHTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-cache, no-store, max-age=0 X-Frame-Options: SAMEORIGIN Transfer-Encoding: chunked {\u0026#34;access_token\u0026#34;:\u0026#34;Xh9Bi8uI6tVBbtuHp_nQzQ\u0026#34;,\u0026#34;token_type\u0026#34;:\u0026#34;bearer\u0026#34;,\u0026#34;expires_in\u0026#34;:3600} Token er gyldig i en time (3600 sekund), men det kan endres med parameter p_token_duration i oauth.create_client.\nMed et token kan prosjekter nå hentes ut med:\ncurl -i -H \u0026#34;Authorization: Bearer Xh9Bi8uI6tVBbtuHp_nQzQ\u0026#34; rio:8080/ords/admin/timereg/prosjekt/ Klienter opprettet med grant type client_credentials brukes i såkalt two-legged flow mellom to servere. For three-legged flow hvor en sluttbruker er involvert og skal godkjenne brukes authorization_code i parameter p_grant_type. I tillegg må p_redirect_uri settes til en url hvor authorization code sendes fra ORDS. Eksempel:\nBEGIN oauth.create_client( p_name =\u0026gt; \u0026#39;Timereg Frontend Administrator\u0026#39;, p_grant_type =\u0026gt; \u0026#39;authorization_code\u0026#39;, p_redirect_uri =\u0026gt; \u0026#39;https://enesi.no/timereg/auth/code/\u0026#39;, p_privilege_names =\u0026gt; \u0026#39;timereg.prosjekt\u0026#39;, p_support_email =\u0026gt; \u0026#39;support@example.com\u0026#39; ); oauth.grant_client_role( p_client_name =\u0026gt; \u0026#39;Timereg Frontend Administrator\u0026#39;, p_role_name =\u0026gt; \u0026#39;Prosjektadministrator\u0026#39; ); COMMIT; END; / Tim Hall aka Oracle-Base.com demonstrerer i en video på YouTube hvordan authorization flow settes opp i tilfelle du trenger litt variasjon.\nORDS støtter også Implicit flow med p_grant_type =\u0026gt; 'implicit'. Referansedokumentasjon til OAUTH-pakken er vist i kap 6 i Developer\u0026rsquo;s Guide Sletting av klient Sletting av klient gjøres slik:\nBEGIN oauth.delete_client(\u0026#39;Webapp Timereg Administrator\u0026#39;); COMMIT; END; / Bruke ekstern IdP IdP som i Identity Provider, feks din bedrifts sentrale løsning, Okta, Google, Azure, Oracle Cloud, etc.\nKort om JWT JSON Web Token (JWT) utstedes av IdP og har en tredelt struktur:\nEt JWT (Wikipedia ) har en payload og en signatur som kan (dvs bør!) sjekkes slik at du er garantert at den kommer fra din IdP. Mange steder brukes det et access token i JWT-format og ikke et såkalt opaque token. Payload er naturligvis i JSON-format og kan lett behandles med JSON-funksjoner i SQL og PL/SQL som vist lenger ned.\nJWT Profile I ORDS kan du lage en JWT-profile pr skjema. Det vil si at ORDS ser etter Bearer token innsendt som JWT i Authorization header. ORDS støtter JWT som benyttes av kjente leverandører. Kravet for at ORDS skal gi tilgang til en ressurs er at JWT må inneholde et scope som er likt med privilege tilordnet ressursen (som vist tidligere med ORDS.DEFINE_PRIVILEGE).\nSyntaks, hentet fra manualen:\nOAUTH.CREATE_JWT_PROFILE ( p_issuer IN VARCHAR2, p_audience IN VARCHAR2, p_jwk_url IN VARCHAR2, p_description IN VARCHAR2 DEFAULT NULL, p_allowed_skew IN NUMBER DEFAULT NULL, p_allowed_age IN NUMBER DEFAULT NULL ); p_issuer og p_audience må stemme med hhv iss og aud claim i JWT som blir utstedt. p_jwk_uri er URI hvor JWT kan sjekkes. Dette kan finnes blant annet som i well known configuration til en OAuth provider. Eksempel fra Google:\ncurl https://accounts.google.com/.well-known/openid-configuration | jq \u0026#39;.jwks_uri\u0026#39; Som gir: \u0026quot;https://www.googleapis.com/oauth2/v3/certs\u0026quot;.\nManual lister opp parametre til kjente ID-leverandører som Okta, IDCS, OCI og Auth0.\nParse Bearer token selv Om du har en egen OAuth-løsning kan det være at formatet ikke er helt som du ønsker. Det kan være at roller er pakket inn i eget claim. I så fall er det være aktuelt å plukke ut JWT selv som vist her:\nl_authorization := regexp_substr(owa_util.get_cgi_env(\u0026#39;Authorization\u0026#39;),\u0026#39;Bearer\\s+(.+)\u0026#39;,1,1,\u0026#39;i\u0026#39;,1); -- Bearer token must be JWT l_token := apex_jwt.decode( p_value =\u0026gt; l_authorization); -- Validate, throws an exception when not valid apex_jwt.validate(p_token =\u0026gt; l_token,p_leeway_seconds =\u0026gt; 10); -- Fetch roles claim from payload l_roles := json_value(l_token.payload,\u0026#39;$.roles\u0026#39;); Kode for å validere signatur er ikke vist her. Ditt API må naturligvis returnere 401 ved manglende token eller manglende rolle/scope i JWT.\nKonklusjon Sikkerhet er sjeldent trivielt, slik er det nesten uavhengig av teknologi, men med ORDS er det overkommelig. Det enkleste eksempelet på bruk av OpenID Connect jeg har sett er i Oracle APEX, se Social Sign-In .\n","permalink":"https://enesi.no/no/2024/05/oauth-2-og-oidc-for-oracle-rest/","summary":"\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/rest-data-services.png.webp\"\n         alt=\"ORDS logo\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eTredje artikkel om Oracle REST Data Services omhandler hvordan et API beskyttes med OAuth 2 og OIDC.\u003c/p\u003e\n\u003ch2 id=\"oauth-2-og-oidc-for-oracle-rest-data-services\"\u003eOAuth 2 og OIDC for Oracle REST Data Services\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://enesi.no/no/2024/04/oracle-rest-data-services/\"\u003eFørste del\u003c/a\u003e\n i denne serien introduserte Oracle REST Data Services (ORDS) og viste hvordan man lager et REST API på tabeller og views med noen få klikk i \u003cem\u003eSQL Developer\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eI \u003ca href=\"https://enesi.no/no/2024/04/skreddersydd-rest-api-med-ords/\"\u003eAndre del\u003c/a\u003e\n ble ORDS API brukt til å definere et mer avansert REST API med litt mer kode.\u003c/p\u003e","title":"OAuth 2 og OIDC for Oracle REST"},{"content":"Artikkel to om Oracle REST Data Services viser hvordan du lett kan lage et tilpasset REST API på egne data i Oracle.\nSkreddersydd REST API med ORDS Første del i denne serien introduserte Oracle REST Data Services (ORDS) og viste hvordan man lager et REST API på tabeller og views med noen få klikk i SQL Developer. I denne delen brukes PL/SQL-pakken ORDS til å definere et API med relativt få linjer med PL/SQL. Det som vises her forutsetter at man har ORDS installert og kjørende som vist i første del.\nTil senere når du trenger å laste ned ORDS, dokumentasjon, ideer eller hjelp i et brukerforum er det lettest å huske URL oracle.com/ords .\nTo tabeller er hentet og forenklet fra et timeregistreringssystem:\nSQL for tabellene CREATE TABLE prosjekt ( id NUMBER GENERATED ALWAYS AS IDENTITY, CONSTRAINT prosjekt_pk PRIMARY KEY ( id ), navn VARCHAR2(100) NOT NULL, beskrivelse VARCHAR2(2000), starttid DATE DEFAULT sysdate NOT NULL, avsluttet DATE, guid RAW(16) DEFAULT sys_guid() ); CREATE TABLE aktivitet ( id NUMBER GENERATED ALWAYS AS IDENTITY, CONSTRAINT aktivitet_pk PRIMARY KEY ( id ), navn VARCHAR2(100) NOT NULL, beskrivelse VARCHAR2(2000), prosjekt_id NUMBER, CONSTRAINT aktivitet_prosjekt_fk FOREIGN KEY ( prosjekt_id ) REFERENCES prosjekt, guid RAW(16) DEFAULT sys_guid() ); Hvorfor ikke AutoREST? Det er selvsagt mulig å legge et enkelt REST API på disse tabellene som vist i forrige post, men typisk vil man ha mer kontroll på sakene og tilpasninger ved å legge et API foran (eller på toppen, alt etter hvordan du ser for deg dette.) Det bør også sies at man kan se for seg mange veier inn til disse tabellene og et REST API er bare en av flere. Med et felles API som alle andre integrasjoner må gå gjennom vil vi få god kontroll. Derfor lages det her et skall i form av PL/SQL-pakker som vårt REST API kaller på. Det er anbefalt en mer avansert sikkerhetsarkitektur med flere skjema, hvor tabeller ligger et sted, og kode i et annet med utvalgte rettigheter på tabellene i det første. Det blir ikke vist her.\nDet er også mulig å benytte AutoREST på PL/SQL-pakker, men da blir det automatisk generert endepunkter og kun POST operasjoner tillatt. Metoden som vises her gir god fleksibilitet for relativt lite ekstra kode.\nAPI fra Oracle i form av PL/SQL-pakken ORDS er beskrevet i Developer\u0026rsquo;s Guide , dvs i kapittel 4 Aktivere REST for et skjema For et nytt skjema (databasebruker) må ORDS aktiveres, for den brukeren man er pålogget som kan det gjøres med:\nbegin ords.enable_schema; commit; end; / Da blir brukernavn en del av URL og det vil man gjerne ikke vise, så vi bruker admin her:\nbegin ords.enable_schema(p_url_mapping_pattern =\u0026gt; \u0026#39;admin\u0026#39;); commit; end; / Det er flere parametre man kan se på, blant annet kan en bruker med DBA-rolle aktivere for annen bruker ved hjelp av parameter p_schema og man kan deaktivere det helt ved å sette p_enabled til false.\nModule, Template, Handler og Parameter Fire begreper er lurt å lære seg, de har en naturlig hierarkisk orden:\nmodule - dette vil typisk være navn på API, feks timereg i dette tilfellet og utgjør del av url etter /ords/. template - tilsvarer del av url som angår et objekt, feks prosjekt, aktivitet, etc handler - For hvert objekt har man HTTP operasjoner (verb) man tillater (GET, POST, PUT, DELETE). Handler er koden som svarer på en HTTP request mot en URL. parameter - Tilknyttes en handler. Disse mapper innsendt JSON til parametre i kode som skal kjøres, og fra retur-parametre som sendes ut i JSON. Hele REST API som bygges opp her defineres i en anonym PL/SQL blokk, men her vises de ulike trinnene individuelt etter hvert som vi går frem. Koden er idempotent, dvs du kan kjøre den flere ganger og den vil overskrive eventuelle tidlige konfigurasjoner for samme modul:\nVi lager en modul som kalles timereg ved hjelp av ords.define_module.\nBEGIN ords.define_module( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_base_path =\u0026gt; \u0026#39;/timereg/\u0026#39;, p_items_per_page =\u0026gt; 25, p_status =\u0026gt; \u0026#39;PUBLISHED\u0026#39;, p_comments =\u0026gt; \u0026#39;REST API til timeregistrering\u0026#39; ); END; I API-et defineres en template for håndtering av prosjekt med rutinen ords.define_template:\nords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av prosjekt\u0026#39;); Senere vil man lage egne templates for å håndtere individuelle prosjekt og aktiviteter til hvert prosjekt.\nTil slutt defineres handlers som håndterer HTTP-kall som kommer inn. I første omgang definerer vi kun for GET:\nKode for å definere handler til GET på alle prosjekter kan se slik ut:\nbegin ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_feed, p_source =\u0026gt; \u0026#39;select navn, beskrivelse,starttid, avsluttet,guid from prosjekt;\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle prosjekt.\u0026#39;); end; Komplett kode så langt er:\nbegin ords.enable_schema(p_url_mapping_pattern =\u0026gt; \u0026#39;admin\u0026#39;); ords.define_module( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_base_path =\u0026gt; \u0026#39;/timereg/\u0026#39;, p_comments =\u0026gt; \u0026#39;REST API til timeregistrering\u0026#39; ); ords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_feed, p_source =\u0026gt; \u0026#39;select navn, beskrivelse,starttid, avsluttet, rawtohex(guid) \u0026#34;uid\u0026#34; from prosjekt\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle prosjekt.\u0026#39;); commit; end; / Om vi legger inn en rad manuelt i tabellen kan vi teste at en vanlig GET fungerer:\ncurl rio:8080/ords/admin/timereg/prosjekt/ | jq En forklaring på url over: ORDS kjøres på en lab-server rio på port 8080. ORDS servlet er satt opp med context root /ords som er standard. /admin er base path tilknyttet skjema som definert i ords.enable_schema, /timereg er definert i ords.define_module og /prosjekt er definert i ords.define_template\nEksempel på svar fra ORDS:\n{ \u0026#34;items\u0026#34;: [ { \u0026#34;navn\u0026#34;: \u0026#34;Timeregistrering applikasjon\u0026#34;, \u0026#34;beskrivelse\u0026#34;: \u0026#34;Ny applikasjon for registrering av timer\u0026#34;, \u0026#34;starttid\u0026#34;: \u0026#34;2024-04-27T14:36:27Z\u0026#34;, \u0026#34;avsluttet\u0026#34;: null, \u0026#34;guid\u0026#34;: \u0026#34;FxQWW/CnCdTgY2QCAArGLg==\u0026#34; } ], \u0026#34;hasMore\u0026#34;: false, \u0026#34;limit\u0026#34;: 25, \u0026#34;offset\u0026#34;: 0, \u0026#34;count\u0026#34;: 1, \u0026#34;links\u0026#34;: [ { \u0026#34;rel\u0026#34;: \u0026#34;self\u0026#34;, \u0026#34;href\u0026#34;: \u0026#34;http://rio:8080/ords/admin/timereg/prosjekt/\u0026#34; }, { \u0026#34;rel\u0026#34;: \u0026#34;describedby\u0026#34;, \u0026#34;href\u0026#34;: \u0026#34;http://rio:8080/ords/admin/metadata-catalog/timereg/prosjekt/\u0026#34; }, { \u0026#34;rel\u0026#34;: \u0026#34;first\u0026#34;, \u0026#34;href\u0026#34;: \u0026#34;http://rio:8080/ords/admin/timereg/prosjekt/\u0026#34; } ] } PL/SQL API En pakke er laget for å legge inn, oppdatere og slette data. Den har p.t. følgende publiserte rutiner:\nCREATE OR REPLACE PACKAGE prosjekt_adm AS FUNCTION nytt_prosjekt ( -- Denne funksjonen brukes ikke fra REST p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE DEFAULT sysdate, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL ) RETURN prosjekt.id%TYPE; PROCEDURE nytt_prosjekt ( p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE DEFAULT sysdate, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL, p_guid OUT VARCHAR2 ); PROCEDURE oppdater_prosjekt ( p_guid IN VARCHAR2, p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL ); PROCEDURE slett_prosjekt ( p_guid IN VARCHAR2 ); END prosjekt_adm; Resten av koden til pakkene (package body) ligger nederst. Det må bemerkes at dette er langt fra produksjonsklart. Ved å bruke PL/SQL her kan man forbedre feilsjekk og implementasjon forøvrig selv om et fast API ivaretas. Man kan også skreddersy feilmeldinger som blir sendt tilbake i JSON-format.\nFlere handlers En handler for POST-operasjon opprettes slik:\nords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.nytt_prosjekt ( p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_starttid =\u0026gt; :starttid, p_avsluttet =\u0026gt; :avsluttet, p_guid =\u0026gt; :uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppretter et prosjekt.\u0026#39;); ords.define_parameter( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_name =\u0026gt; \u0026#39;uid\u0026#39; , p_bind_variable_name =\u0026gt; \u0026#39;uid\u0026#39;, p_source_type =\u0026gt; \u0026#39;RESPONSE\u0026#39;, p_param_type =\u0026gt; \u0026#39;STRING\u0026#39;, p_access_method =\u0026gt; \u0026#39;OUT\u0026#39;, p_comments =\u0026gt;\u0026#39;UID returned from database.\u0026#39;); Siden vi ønsker å få ut uid må den defineres som vist med ords.define_parameter. De andre bind-variablene blir implisitt definert.\nFørste POST Følgende json dokument legges i en fil med navn prosjekt.json:\n{ \u0026#34;navn\u0026#34;: \u0026#34;Testprosjekt\u0026#34;, \u0026#34;beskrivelse\u0026#34;: \u0026#34;Prosjekt for all testing\u0026#34; } Dette kan sendes inn med feks curl:\ncurl -X POST -H \u0026#39;Content-Type: application/json\u0026#39; -d@prosjekt.json rio:8080/ords/admin/timereg/prosjekt/ Verdt å merke seg at header med Content-Type: application/json må være med som vist over, ellers får man feilmelding som kan være vanskelig å finne ut av; innsendt JSON blir ikke riktig tolket og bind-variablene blir ikke definert.\nRespons er en kort JSON som inneholder uid:\n{\u0026#34;uid\u0026#34;:\u0026#34;1716D650145C0DF0E0636402000AE8A2\u0026#34;} uid fra respons bruker vi senere når vi skal opprette aktiviteter.\nParametre og datohåndtering Merk at ikke alle parametre er obligatoriske, PL/SQL-rutinene er laget for å håndtere parametre med standardverdier når de mangler. For de som blir sendt i JSON-format vil ORDS definere dem automagisk. Unntak er om det benyttes navn som ikke er lovlige i PL/SQL.\nOm vi ønsker å sende inn starttid, så håndterer ORDS ISO-8601 på strak arm:\n{ \u0026#34;navn\u0026#34;: \u0026#34;Testprosjekt II\u0026#34;, \u0026#34;beskrivelse\u0026#34;: \u0026#34;Prosjekt for enda mer testing\u0026#34;, \u0026#34;starttid\u0026#34;: \u0026#34;2024-04-27T14:36:27Z\u0026#34; } Det er ikke nødvendig med konvertering med to_date noe sted i koden for at dette skal fungere.\nORDS gjør commit I koden som betjener hvert endepunkt og operasjon ligger det ikke eksplisitt commit; ORDS gjør en commit tilslutt om alt går bra - noe som gir mening siden HTTP er en stateless protokoll.\nOperasjoner på individuelt prosjekt Neste trinn er å definere operasjoner for å hente, oppdatere og slette et individuelt prosjekt. De fleste som bruker et REST API vil forvente å kunne gjøre det mot en URL som vist over med UID lagt til. Følgende oppretter en ny template og tre handlers for GET, PUT og DELETE:\nords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_item, p_source =\u0026gt; q\u0026#39;[ select navn, beskrivelse,starttid, avsluttet, rawtohex(guid) \u0026#34;uid\u0026#34; from prosjekt where guid=hextoraw(:uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer et prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;PUT\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.oppdater_prosjekt( p_guid =\u0026gt; :uid, p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_starttid =\u0026gt; :starttid, p_avsluttet =\u0026gt; :avsluttet); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppdaterer et prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;DELETE\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.slett_prosjekt ( p_guid =\u0026gt; :uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Sletter et prosjekt.\u0026#39;); Med dette lagt til kan man hente et enkelt prosjekt, oppdatere det og slette det med hhv:\ncurl rio:8080/ords/admin/timereg/prosjekt/1716D650145E0DF0E0636402000AE8A2 curl -X PUT -H \u0026#34;Content-Type: application/json\u0026#34; -d@prosjekt_put.json \\ rio:8080/ords/admin/timereg/prosjekt/1716D650145E0DF0E0636402000AE8A curl -X DELETE rio:8080/ords/admin/timereg/prosjekt/1716D650145E0DF0E0636402000AE8A2 Parameter uid er implisitt definert gjennom p_pattern i ords.define_handler.\nSource type De ulike handlers har forskjellig p_source_type som må settes iht koden som kjøres:\nords.source_type_collection_feed - Select som returnerer flere rader blir kjørt, ORDS returnerer JSON array ords.source_type_collection_item - Select som returnerer en rad, ORDS returnerer et objekt. ords.source_type_plsql - PL/SQL kjøres og ORDS mapper IN og OUT parametre. Aktiviteter til et prosjekt For å håndtere aktiviteter er det laget en egen forenklet pakke for det. Her inneholder den kun en rutine for å opprette en ny aktivitet:\nCREATE OR REPLACE PACKAGE aktivitet_adm AS PROCEDURE ny_aktivitet ( p_navn IN aktivitet.navn%TYPE, p_beskrivelse IN aktivitet.beskrivelse%TYPE, p_prosjekt_guid IN VARCHAR2, p_guid OUT VARCHAR2 ); END aktivitet_adm; / Siden en aktivitet er knyttet til et bestemt prosjekt vil det være naturlig å legge /aktivitet/ bakerst på URL til et bestemt prosjekt. Følgende kode oppretter template og to handlers for å liste ut alle aktiviteter til et prosjekt og opprette en ny aktivitet knyttet til et bestemt prosjekt:\nords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av aktiviteter til et prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_feed, p_source =\u0026gt; q\u0026#39;[ select p.navn prosjektnavn, a.navn aktivitetsnavn, a.beskrivelse aktivitetsbeskrivelse, rawtohex(p.guid) prosjekt_uid, rawtohex(a.guid) aktivitet_uid from prosjekt p join aktivitet a on p.id = a.prosjekt_id where p.guid=hextoraw(:uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle aktiviteter for prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin aktivitet_adm.ny_aktivitet ( p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_prosjekt_guid =\u0026gt; :uid, p_guid =\u0026gt; :aktivitet_uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppretter en aktivitet for prosjekt.\u0026#39;); ords.define_parameter( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_name =\u0026gt; \u0026#39;aktivitet_uid\u0026#39; , p_bind_variable_name =\u0026gt; \u0026#39;aktivitet_uid\u0026#39;, p_source_type =\u0026gt; \u0026#39;RESPONSE\u0026#39;, p_param_type =\u0026gt; \u0026#39;STRING\u0026#39;, p_access_method =\u0026gt; \u0026#39;OUT\u0026#39;, p_comments =\u0026gt;\u0026#39;UID til opprettet aktivitet.\u0026#39;); Eksempel på POST som oppretter en ny aktivitet for et prosjekt:\ncurl -X POST -H \u0026#39;Content-Type: application/json\u0026#39; -d@aktivitet.json rio:8080/ords/admin/timereg/prosjekt/1714165BF0A709D4E0636402000AC62E/aktivitet/ Siste REST - individuell aktivitet Denne koden definerer GET på en bestemt aktivitet:\nords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/:aktivitet_uid\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av enkelt aktivitet til et prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/:aktivitet_uid\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_item, p_source =\u0026gt; q\u0026#39;[ select p.navn prosjektnavn, a.navn aktivitetsnavn, a.beskrivelse aktivitetsbeskrivelse, rawtohex(p.guid) prosjekt_uid, rawtohex(a.guid) aktivitet_uid from prosjekt p join aktivitet a on p.id = a.prosjekt_id where p.guid=hextoraw(:uid) and a.guid = hextoraw(:aktivitet_uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle aktiviteter for prosjekt.\u0026#39;); Eksempel på GET mot en aktivitet:\ncurl http://rio:8080/ords/admin/timereg/prosjekt/1714165BF0A709D4E0636402000AC62E/aktivitet/1716D650145F0DF0E0636402000AE8A2 Det bør være en overkommelig oppgave å definere handlers for PUT og DELETE mot en enkeltaktivitet.\n405 Method Not Allowed Så langt har vi ikke definert hvordan PUT og DELETE mot en aktivitet skal håndteres; derfor får man HTTP 405 - Method Not Allowed når man forsøker seg på det. ORDS sjekker automatisk for hvilke operasjoner som er definert. Om en URL ikke kan håndteres i definerte handlers så vil man naturligvis få HTTP 404.\nHva er greia med UID? Om du lurer på hvorfor UID brukes og ikke primærnøkkel (ID) så er det for å unngå scanning og masseuthenting via ID. ID stiger sekvensielt og om den var en del av URL i stedet for UID vil API-et bli mer sårbart for slikt misbruk.\nTips til slutt Dersom du bruker verktøy som Postman så sjekk hvilke headere som sendes inn. Om det sendes inn User-Agent type nettleser vil ORDS gjerne svare med html når feil oppstår. Fra Curl som vist her returnerer den JSON også ved feil.\nDet er mye funksjonalitet som ikke er dekket her. Blant annet sikkerhet. Vårt API er vid åpent. OAuth 2.0, OIDC et al er tema i neste post. Sjekk dokumentasjon og søk etter tips fra blant annet Jeff Smith Forhåpentligvis har denne gjennomgangen vist hvordan man gradvis kan bygge opp et REST API i en logisk struktur og tilpasses etter hvert.\nREST API så langt Komplett anonym PL/SQL-kode for REST API som er definert så langt, denne blokken er blitt så lang at den kunne vært splittet opp i en blokk pr template for eksempel:\nbegin ords.enable_schema(p_url_mapping_pattern =\u0026gt; \u0026#39;admin\u0026#39;); ords.define_module( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_base_path =\u0026gt; \u0026#39;/timereg/\u0026#39;, p_comments =\u0026gt; \u0026#39;REST API til timeregistrering\u0026#39; ); ords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_feed, p_source =\u0026gt; \u0026#39;select navn, beskrivelse,starttid, avsluttet, rawtohex(guid) \u0026#34;uid\u0026#34; from prosjekt\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.nytt_prosjekt ( p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_starttid =\u0026gt; :starttid, p_avsluttet =\u0026gt; :avsluttet, p_guid =\u0026gt; :uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppretter et prosjekt.\u0026#39;); ords.define_parameter( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_name =\u0026gt; \u0026#39;uid\u0026#39; , p_bind_variable_name =\u0026gt; \u0026#39;uid\u0026#39;, p_source_type =\u0026gt; \u0026#39;RESPONSE\u0026#39;, p_param_type =\u0026gt; \u0026#39;STRING\u0026#39;, p_access_method =\u0026gt; \u0026#39;OUT\u0026#39;, p_comments =\u0026gt;\u0026#39;UID returned from database.\u0026#39;); ords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_item, p_source =\u0026gt; q\u0026#39;[ select navn, beskrivelse,starttid, avsluttet, rawtohex(guid) \u0026#34;uid\u0026#34; from prosjekt where guid=hextoraw(:uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer et prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;PUT\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.oppdater_prosjekt( p_guid =\u0026gt; :uid, p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_starttid =\u0026gt; :starttid, p_avsluttet =\u0026gt; :avsluttet); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppdaterer et prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid\u0026#39;, p_method =\u0026gt; \u0026#39;DELETE\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin prosjekt_adm.slett_prosjekt ( p_guid =\u0026gt; :uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Sletter et prosjekt.\u0026#39;); ords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av aktiviteter til et prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_feed, p_source =\u0026gt; q\u0026#39;[ select p.navn prosjektnavn, a.navn aktivitetsnavn, a.beskrivelse aktivitetsbeskrivelse, rawtohex(p.guid) prosjekt_uid, rawtohex(a.guid) aktivitet_uid from prosjekt p join aktivitet a on p.id = a.prosjekt_id where p.guid=hextoraw(:uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle aktiviteter for prosjekt.\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_source_type =\u0026gt; ords.source_type_plsql, p_source =\u0026gt; q\u0026#39;[ begin aktivitet_adm.ny_aktivitet ( p_navn =\u0026gt; :navn, p_beskrivelse =\u0026gt; :beskrivelse, p_prosjekt_guid =\u0026gt; :uid, p_guid =\u0026gt; :aktivitet_uid); end;]\u0026#39;, p_comments =\u0026gt; \u0026#39;Oppretter en aktivitet for prosjekt.\u0026#39;); ords.define_parameter( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/\u0026#39;, p_method =\u0026gt; \u0026#39;POST\u0026#39;, p_name =\u0026gt; \u0026#39;aktivitet_uid\u0026#39; , p_bind_variable_name =\u0026gt; \u0026#39;aktivitet_uid\u0026#39;, p_source_type =\u0026gt; \u0026#39;RESPONSE\u0026#39;, p_param_type =\u0026gt; \u0026#39;STRING\u0026#39;, p_access_method =\u0026gt; \u0026#39;OUT\u0026#39;, p_comments =\u0026gt;\u0026#39;UID til opprettet aktivitet.\u0026#39;); ords.define_template( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/:aktivitet_uid\u0026#39;, p_comments =\u0026gt; \u0026#39;Administrasjon av enkelt aktivitet til et prosjekt\u0026#39;); ords.define_handler( p_module_name =\u0026gt; \u0026#39;timereg\u0026#39;, p_pattern =\u0026gt; \u0026#39;/prosjekt/:uid/aktivitet/:aktivitet_uid\u0026#39;, p_method =\u0026gt; \u0026#39;GET\u0026#39;, p_source_type =\u0026gt; ords.source_type_collection_item, p_source =\u0026gt; q\u0026#39;[ select p.navn prosjektnavn, a.navn aktivitetsnavn, a.beskrivelse aktivitetsbeskrivelse, rawtohex(p.guid) prosjekt_uid, rawtohex(a.guid) aktivitet_uid from prosjekt p join aktivitet a on p.id = a.prosjekt_id where p.guid=hextoraw(:uid) and a.guid = hextoraw(:aktivitet_uid)]\u0026#39;, p_comments =\u0026gt; \u0026#39;Returnerer alle aktiviteter for prosjekt.\u0026#39;); commit; end; / Package bodies Package body til rutinene som brukes fra ORDS vises under.\nCREATE OR REPLACE PACKAGE BODY prosjekt_adm AS FUNCTION nytt_prosjekt ( p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE DEFAULT sysdate, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL ) RETURN prosjekt.id%TYPE AS l_id prosjekt.id%TYPE; BEGIN INSERT INTO prosjekt ( navn, beskrivelse, starttid, avsluttet ) VALUES ( p_navn, p_beskrivelse, nvl(p_starttid,sysdate), p_avsluttet ) RETURNING id INTO l_id; RETURN l_id; END nytt_prosjekt; PROCEDURE nytt_prosjekt ( p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE DEFAULT sysdate, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL, p_guid OUT VARCHAR2 ) AS BEGIN INSERT INTO prosjekt ( navn, beskrivelse, starttid, avsluttet ) VALUES ( p_navn, p_beskrivelse, nvl(p_starttid,sysdate), p_avsluttet ) RETURNING rawtohex(guid) INTO p_guid; END nytt_prosjekt; PROCEDURE oppdater_prosjekt ( p_guid IN VARCHAR2, p_navn IN prosjekt.navn%TYPE, p_beskrivelse IN prosjekt.beskrivelse%TYPE, p_starttid IN prosjekt.starttid%TYPE, p_avsluttet IN prosjekt.avsluttet%TYPE DEFAULT NULL ) AS BEGIN UPDATE prosjekt SET navn = p_navn, beskrivelse = p_beskrivelse, avsluttet = p_avsluttet WHERE guid = hextoraw(p_guid); END oppdater_prosjekt; PROCEDURE slett_prosjekt ( p_guid IN VARCHAR2 ) AS BEGIN DELETE FROM prosjekt WHERE guid = hextoraw(p_guid); END slett_prosjekt; END prosjekt_adm; / CREATE OR REPLACE PACKAGE BODY aktivitet_adm AS PROCEDURE ny_aktivitet ( p_navn IN aktivitet.navn%TYPE, p_beskrivelse IN aktivitet.beskrivelse%TYPE, p_prosjekt_guid IN VARCHAR2, p_guid OUT VARCHAR2 ) AS l_prosjekt_id prosjekt.id%TYPE; BEGIN SELECT id INTO l_prosjekt_id FROM prosjekt WHERE guid = hextoraw(p_prosjekt_guid); INSERT INTO aktivitet ( navn, beskrivelse, prosjekt_id ) VALUES ( p_navn, p_beskrivelse, l_prosjekt_id ) RETURNING guid INTO p_guid; END ny_aktivitet; END aktivitet_adm; / ","permalink":"https://enesi.no/no/2024/04/skreddersydd-rest-api-med-ords/","summary":"\u003cp\u003eArtikkel to om Oracle REST Data Services viser hvordan du lett kan lage et tilpasset REST API på egne data i Oracle.\u003c/p\u003e\n\u003ch2 id=\"skreddersydd-rest-api-med-ords\"\u003eSkreddersydd REST API med ORDS\u003c/h2\u003e\n\u003cp\u003e\u003ca href=\"https://enesi.no/no/2024/04/oracle-rest-data-services/\"\u003eFørste del\u003c/a\u003e\n i denne serien introduserte Oracle REST Data Services (ORDS) og viste hvordan man lager et REST API på tabeller og views med noen få klikk i \u003cem\u003eSQL Developer\u003c/em\u003e. I denne delen brukes PL/SQL-pakken ORDS til å definere et API med relativt få linjer med PL/SQL. Det som vises her forutsetter at man har ORDS installert og kjørende som vist i første del.\u003c/p\u003e","title":"Skreddersydd REST API med ORDS"},{"content":" Oracle REST Data Services er sannsynligvis den enkleste måten å dele data som ligger i en Oracle database.\nOracle REST Data Services Mer deling av data er et uttalt mål for mange organisasjoner, spesielt i offentlig sektor. Tilbyr du et REST API til dine data åpner det for at mange kan hente ut det de trenger på en lettvint måte. Skal noen sende data til deg er REST også den enkleste måte å gjøre det på.\nREST har mange fordeler, det er utbredt og enkelt, spesielt om man sammenligner med standarder som var mer utbredt før (feks SOAP). Nå tilbys REST stadig mer, se for eksempel på Felles datakatalog på data.norge.no , selv Chuck Norris vitser tilbys nå gjennom REST, se api.chucknorris.io Oracle tilbyr Oracle REST Data Services (ORDS) uten ekstra lisenskostnader fra oracle.com/ords . Etter flere års erfaring har jeg ikke sett et REST API som henter data fra en Oracle database raskere enn hva ORDS presterer; ytelsen er imponerende selv på beskjeden infrastruktur.\nEn ferdig installasjon består av to deler, en Java servlet gående på en applikasjonsserver og et nytt API i databasen.\nOm du vil overlate installasjon til andre og se på utviklingsmuligheter i ORDS så fortsett lenger nede i artikkelen.\nInstallasjon Nedlasting består av kun en zip-fil som pakkes ut på en applikasjonsserver eller annet passende miljø. Bruk denne linken https://download.oracle.com/otn_software/java/ords/ords-latest.zip så får du alltid siste versjon. Den kan lastes ned direkte med feks wget eller curl uten behov for å klikke seg gjennom en lisensavtale. Dagens versjon, 24.1 er på 116MB komprimert.\nKravene til ORDS er beskjedne, men du må ha Java versjon 11 eller nyere. ORDS installeres gjerne av en databaseadministrator; du trenger SYS passord til databasen som skal brukes. Det finnes noen varianter på hvordan man kan gjøre en installasjon, men her vises den enkleste mulige slik at du kan komme fort i gang og se hvor enkelt det kan gjøres; installasjon i en pluggable database (PDB). I eksempel under brukes wget, men curl -O gjør samme nytte. Miljøet må være klart slik at java ligger i PATH.\nwget https://download.oracle.com/otn_software/java/ords/ords-latest.zip mkdir ords-24.1 mkdir ordsconfig ln -s ords-24.1 ords-latest cd ords-latest unzip ../ords-latest.zip bin/ords --config ../ordsconfig install Her får du tre valg:\nEnter a number to select the database connection type to use [1] Basic (host name, port, service name) [2] TNS (TNS alias, TNS directory) [3] Custom database URL Choose [1]: Velg 1 som foreslått. Oppgi navn til verten hvor databasen, port er typisk 1521 som vist, service navn er service som registrert i database listener. Her bruker jeg en database som jeg opprettet i forbindelse med konferansen neste uke, OUGN 2024 . På spørsmål Enter the administrator username: velg SYS:\nEnter the database host name [localhost]: rio Enter the database listen port [1521]: Enter the database service name [orcl]: ougn2024 Provide database user name with administrator privileges. Enter the administrator username: SYS Enter the database password for SYS AS SYSDBA: Retrieving information. ORDS is not installed in the database. ORDS installation is required. Enter a number to update the value or select option A to Accept and Continue [1] Connection Type: Basic [2] Basic Connection: HOST=rio PORT=1521 SERVICE_NAME=ougn2024 Administrator User: SYS AS SYSDBA [3] Database password for ORDS runtime user (ORDS_PUBLIC_USER): \u0026lt;generate\u0026gt; [4] ORDS runtime user and schema tablespaces: Default: SYSAUX Temporary TEMP [5] Additional Feature: Database Actions [6] Configure and start ORDS in Standalone Mode: Yes [7] Protocol: HTTP [8] HTTP Port: 8080 [A] Accept and Continue - Create configuration and Install ORDS in the database [Q] Quit - Do not proceed. No changes Choose [A]: Valgene som foreslått her er OK (Database Actions gir andre muligheter som får bli tema en annen gang.) Den setter et generert passord for en ny bruker ORDS_PUBLIC_USER i databasen. Passordet blir liggende kryptert i en konfigurasjonsfil. Det kan lett endres senere, men bortsatt fra korrekt konfigurasjon så trenger du ikke dette passordet til noe annet. Standard er at ORDS lytter på port 8080, det kan også endres senere. Etter installasjon er ferdig så starter den i Standalone Mode (linje 6). Om du vil kan du avbryte den med Ctrl-C og starte den opp igjen med\nbin/ords --config ../ordsconfig serve I et produksjonsmiljø vil man naturligvis plassere denne i infrastruktur som man ellers vil gjøre med en applikasjon/servlet. I eksempel her kjøres ORDS i standalone mode, men det kan også deployes til Apache Tomcat eller Oracle Weblogic. Og siden den er stateless er det problemfritt å kjøre flere i parallel.\nFor mer informasjon om installasjon, se Installation and Configuration Guide Enkel testing av REST i databasen Eksempler under er gjort i SQL Developer .\nDen absolutte enkleste måte å tilby REST på tabeller og views er å bruke AutoREST. Det gjør det mulig å bruke de vanlige operasjonene som GET, POST, PUT og DELETE på tabeller/views og det kan fungere greit til internt bruk om man ikke er redd for uautorisert oppdatering (det kan håndteres med roller senere eller i definisjon av et view som ikke tillater det).\nEn bruker ORDS_DEMO er opprettet og en CSV-fil med dagens kommuner er lastet ned fra SSB via data.norge.no.\nFørst aktiveres ORDS på skjemaet (bruker). Det gjøres ved å høyreklikke på connection til databasen og velge nest-siste linje i meny som vist her:\nHuk av på Enable schema og ta bort hake ved Authorization required. Du kan velge et annet alias en brukernavn som foreslås, det kan være greit å ikke eksponere brukernavnet ut.\nKlikk på Next og Finish for å fullføre denne delen.\nNeste trinn er å aktivere REST på en tabell. Det gjøres ved å høyreklikke på tabellen som vist og velge nest-siste valg igjen:\nPå samme måte aktiveres det ved å klikke på Enable object og ta bort Authorization required\nNå kan data nås med nettleser, curl eller annet egnet verktøy for REST API (Postman, Insomnia og en haug med andre).\nORDS i denne demoen går på en server rio og port 8080. Context root til ORDS servlet er standard /ords/ (kan endres i konfigurasjon). I tillegg valgte jeg data som alias for brukeren og kommuner for denne tabellen. Hele URL-en blir i dette tilfellet http://rio:8080/ords/data/kommuner/. På linux bruker jeg gjerne jq til formatering av JSON:\ncurl http://rio:8080/ords/data/kommuner/ | jq Denne vil hente de 25 første radene med linker som støtter paginering, kun de siste linjene er vist her:\nMerk at denne inkluderer link til metadata-catalog. Den vil igjen referere til Open API catalog for datasettet.\nI tabellen ble kolonnen code satt som primærnøkkel. (CSV-filen ble importert fra SSB med kolonnenavn som i CSV-fil, men tomme kolonner ble droppet). Dette er kommunenummer. Søk på Oslo-kommune som har nummer 0301 kan gjøres med http://rio:8080/ords/data/kommuner/0301. Kolonnen name inneholder kommunenavn. Et søk på eksakt verdi feks Sunnfjord kan gjøres med URL 'http://rio:8080/ords/data/kommuner/?q={\u0026quot;name\u0026quot;:\u0026quot;Sunnfjord\u0026quot;}' Mer om søk er vist i Developer\u0026rsquo;s Guide, 2.3.2 Dersom man ønsker å slette Sunnfjord (hvem har vel ikke det?) som har nummer 4647 kan det gjøres med:\ncurl -X DELETE \u0026#39;http://rio:8080/ords/data/kommuner/4647\u0026#39; Definisjon av REST ved hjelp av SQL og PL/SQL Om man ønsker større kontroll, som for eksempel bestemme hvilke HTTP operasjoner man tillater kan man bruke PL/SQL-pakken ORDS som ble lagt inn ved installasjon. Faktisk er det denne som blir brukt bak kulissene i SQL Developer. For å se SQL som kjøres klikk på fane SQL på siste side:\nBruk av ORDS-pakken er tema i neste post .\n","permalink":"https://enesi.no/no/2024/04/oracle-rest-data-services/","summary":"\u003cfigure\u003e\n    \u003cimg loading=\"lazy\" src=\"/images/ords_logo.png\"\n         alt=\"ORDS logo\" width=\"200px\"/\u003e \n\u003c/figure\u003e\n\n\u003cp\u003eOracle REST Data Services er sannsynligvis den enkleste måten å dele data som ligger i en Oracle database.\u003c/p\u003e\n\u003ch2 id=\"oracle-rest-data-services\"\u003eOracle REST Data Services\u003c/h2\u003e\n\u003cp\u003eMer deling av data er et uttalt mål for mange organisasjoner, spesielt i offentlig sektor. Tilbyr du et REST API til dine data åpner det for at mange kan hente ut det de trenger på en lettvint måte. Skal noen sende data til deg er REST også den enkleste måte å gjøre det på.\u003c/p\u003e","title":"Oracle REST Data Services"},{"content":"Oracle Spatial kommer med over 6000 referansesystem (Coordinate systems), men mangler SRID 5973. Denne brukes i Nasjonal vegdatabank (NVDB), se innlegg i vegdata.no . Merk at NVDB har for tiden to versjoner av sitt API. I V3 bruker 5973 som standard om man ikke ber om noe annet, se beskrivelse av endepunkt .\nInformasjon om ulike koordinatsystem finnes på epsg.io . Der finnes også for EPSG:5973, men yttergrensene definert der er bare en mindre del av Norge, se https://epsg.io/5973 .\nFølgende SQL kjøres som SYSTEM for å legge inn SRID 5973 til bruk i Oracle Spatial:\ninsert into sdo_datums ( DATUM_ID, DATUM_NAME, DATUM_TYPE, ELLIPSOID_ID, PRIME_MERIDIAN_ID, INFORMATION_SOURCE, DATA_SOURCE, SHIFT_X, SHIFT_Y, SHIFT_Z, ROTATE_X, ROTATE_Y, ROTATE_Z, SCALE_ADJUST, IS_LEGACY, LEGACY_CODE) values ( 1096, \u0026#39;Norway Normal Null 2000\u0026#39;, \u0026#39;VERTICAL\u0026#39;, null, null, \u0026#39;Norwegian Mapping Authority\u0026#39;, \u0026#39;OGP\u0026#39;, NULL, NULL, NULL, NULL, NULL, NULL, NULL, \u0026#39;FALSE\u0026#39;, NULL); INSERT INTO sdo_coord_ref_system ( srid, coord_ref_sys_name, coord_ref_sys_kind, coord_sys_id, datum_id, geog_crs_datum_id, source_geog_srid, projection_conv_id, cmpd_horiz_srid, cmpd_vert_srid, information_source, data_source, is_legacy, legacy_code, legacy_wktext, legacy_cs_bounds, is_valid, supports_sdo_geometry ) VALUES ( \u0026#39;5941\u0026#39;, \u0026#39;NN2000 height\u0026#39;, \u0026#39;VERTICAL\u0026#39;, \u0026#39;6499\u0026#39;, \u0026#39;5206\u0026#39;, \u0026#39;5206\u0026#39;, NULL, NULL, NULL, NULL, \u0026#39;Norwegian Mapping Authority.\u0026#39;, \u0026#39;EPSG\u0026#39;, \u0026#39;FALSE\u0026#39;, NULL, NULL, NULL, \u0026#39;TRUE\u0026#39;, \u0026#39;TRUE\u0026#39; ); INSERT INTO sdo_coord_ref_system ( srid, coord_ref_sys_name, coord_ref_sys_kind, coord_sys_id, datum_id, geog_crs_datum_id, source_geog_srid, projection_conv_id, cmpd_horiz_srid, cmpd_vert_srid, information_source, data_source, is_legacy, legacy_code, legacy_wktext, legacy_cs_bounds, is_valid, supports_sdo_geometry ) VALUES ( \u0026#39;5973\u0026#39;, \u0026#39;ETRS89 / UTM zone 33N + NN2000 height\u0026#39;, \u0026#39;COMPOUND\u0026#39;, NULL, NULL, NULL, NULL, NULL, \u0026#39;25833\u0026#39;, \u0026#39;5941\u0026#39;, \u0026#39;Norwegian Mapping Authority\u0026#39;, \u0026#39;EPSG\u0026#39;, \u0026#39;FALSE\u0026#39;, NULL, NULL, NULL, \u0026#39;TRUE\u0026#39;, \u0026#39;TRUE\u0026#39; ); commit; ","permalink":"https://enesi.no/no/2023/04/legg-til-referansesystem-5979-til-oracle-spatial/","summary":"\u003cp\u003eOracle Spatial kommer med over 6000  referansesystem (\u003cem\u003eCoordinate systems\u003c/em\u003e), men  mangler SRID 5973. Denne brukes i Nasjonal vegdatabank (NVDB), se \u003ca href=\"https://www.vegdata.no/2020/03/11/nytt-referansesystem-nvdb/\" target=\"_blank\" rel=\"noopener\"\u003einnlegg i vegdata.no\u003c/a\u003e\n. Merk at NVDB har for tiden to versjoner av sitt API. I V3 bruker 5973 som standard om man ikke ber om noe annet, se \u003ca href=\"https://nvdbapiles-v3.atlas.vegvesen.no/dokumentasjon/openapi/#/Vegnett/get_posisjon\" target=\"_blank\" rel=\"noopener\"\u003ebeskrivelse av endepunkt\u003c/a\u003e\n.\u003c/p\u003e\n\u003cp\u003eInformasjon om ulike koordinatsystem finnes på \u003ca href=\"https://epsg.io\" target=\"_blank\" rel=\"noopener\"\u003eepsg.io\u003c/a\u003e\n. Der finnes også for EPSG:5973, men yttergrensene definert der er bare en mindre del av Norge, se \u003ca href=\"https://epsg.io/5973\" target=\"_blank\" rel=\"noopener\"\u003ehttps://epsg.io/5973\u003c/a\u003e\n.\u003c/p\u003e","title":"Legg til referansesystem 5979 til Oracle Spatial"},{"content":"Litt sent ute Ber du folk om å nevne skyleverandører kan de fleste innen IT ramse opp Amazon Web Services (AWS), Azure og Google Cloud Platform (GCP). Forbausende mange har ikke hørt om Oracle Cloud, til tross for at Oracle database har hatt opp mot halvparten av det profesjonelle databasemarkedet.\nDet kan være at Oracle Cloud lenge ikke var spesielt bra. Selv trofaste teknologer fra brukermiljøet til Oracle klagde høylytt om hvor vanskelig det var å komme i gang uten å betale dyrt, og at det var langt unna den modenhet og brukervennlighet som for eksempel AWS kunne tilby.\nMen den som tviholder på slike synspunkter lenge i IT-bransjen uten å ta en ny sjekk av og til lurer seg selv. Oracle Cloud Infrastructure (OCI) står ikke stille og konkurrerer nå på pris og funksjonalitet.\nKom i gang gratis og uten risiko Oracle var kanskje sent ute med å tilby en god skyløsning, men gratistilbudet i Oracle Free Tier er det vanskelig å slå, og det blir stadig bedre.\nEr du utålmodig kan du gå rett til Oracle Free Tier og sette i gang. Ja, du trenger et kredittkort, men Oracle lover at så lenge din konto ikke er oppgradert fra free tier blir du ikke belastet. Etter over et år hvor jeg selv har brukt dette privat og i jobb har jeg ikke opplevd en eneste belastning fra Oracle på kortet.\nImage by Michal Jarmoluk, Pixabay\nDette er faktisk viktig; studenter med små budsjett har fått ubehagelige overraskelser hos AWS etter å ha brukt feil tjeneste eller utført en konfigurasjon de ikke helt forstod.\nEtter noen år i bransjen har jeg hørt mange historier om skyhøye regninger for relativt enkle prosjekt.\nFree Tier er altså en ekte try before you buy-løsning. Har du en idé, men ikke er tilstrekkelig overbevist om at den er verdt en stor investering kan du jo bare prøve. Proof of Concept (POC) som vi gjerne kaller det bør ikke koste mye eller kreve store investeringer i starten. Enten skyløsningen er betalt eller ikke, kan man alltids ta ned det man har laget når POC er ferdig. I Free Tier kan du la det stå til det stopper av seg selv om du ikke gidder å rydde selv. Om idéen din blir en suksess kan du konvertere til en betalt tjeneste for å skalere opp. Før du gjør det kan du sjekke kostnader med Cost Estimator .\nMange små bedrifter vil ikke trenge en oppskalering, Free Tier er kraftig nok til å betjene flere brukere i en online-løsning.\nGratis for alltid På websiden til Oracle står det: Try Always Free cloud services and get a 30-day trial. Det er altså noen tjenester som er gratis for alltid og noen tjenester du kan teste ut i 30 dager med en ekstra kreditt på $300,- Det betyr at du kan sette i gang med din POC, og om du har lyst å lage en heidundrende server for noen dager så kan du det.\nNoen tjenester du kan lage gratis:\nVirtuelle maskiner (VM) VM-er med ARM-prosessorer Blokkvolum Arkivvolum Autonome Oracle Databaser, NoSQL-databaser Low-code-utvikling med Oracle APEX Lastbalansering Autonome databaser styrer seg selv Infrastruktur i skyen gir mye kortere leveringstid enn hva din lokale IT-avdeling kan ordne om de skal bygge alt fra bunnen av. Unntaket er de få som har stålkontroll og enorme budsjetter. Dessuten slipper man mye av den daglige driften fordi noen et annet sted i verden sjekker at ting er på stell.\nAutonome databaser tar dette enda lenger. Si du er utvikler og kanskje har et litt anstrengt forhold til din lokale DBA, så kan du klare deg uten vedkommende med en autonom database i OCI. Typisk vil tidsfrister ikke tillate at du bruker en uke på å studere indeksering og annet i databasen. Det trenger du altså ikke her.\nRask utvikling med Oracle APEX Low-code er et nytt begrep for utvikling med minimal koding. Det kan jo være at det du trenger nå ikke er veldig komplisert og ikke fortjener en haug med arkitekter, sprinter og et halvt forsvarsbudsjett. Svært subjektivt, men jeg tror ærlig talt at om du legger vekt på følgende så vil få løsninger gi deg bedre score enn Oracle APEX:\nGod brukervennlighet Lave utviklingskostnader Lave driftskostnader Kort tid fra idé til ferdig produkt Høy sikkerhet Rask respons Lite kompleksitet Utviklingsmiljøet i APEX\nHar du et regneark i mange kopier på epost, delt disk og lokal PC, så kan du lett erstatte dette med APEX og i tillegg få:\nPublikasjon i nettleser Tilgangsstyring med brukernavn og passord, eller Single Sign-On via AD eller sosiale nettverk. Logging av endringer En versjon Sikerhetskopi Integritetssjekk Mer avansert analyse og rapporter Rask integrasjon med REST, SOAP og andre API. Sjekk ut apex.oracle.com og se om det er noe du liker. Og forresten, APEX koster ingenting ekstra.\nDevOps og Infrastructure as Code (IaC) Terraform fungerer utmerket med OCI. HashiCorp har også laget god støtte for OCI i Vault, Nomad og Consul. Oracle har også utviklet moduler for Ansible .\nDet er en god investering å automatisere installasjon av infrastruktur. Men dette er et stort tema i seg selv. Her er en samleside fra Oracle med støtte til utviklere og verktøy .\nEt vell av tjenester Denne oversikten viser tjenester som kan kalles med REST API. Den blir stadig lengre. Har du lyst å prøve ut sentiment analysis på tekster kan du gjøre det med Oracle Cloud Infrastructure Artificial Intelligence Services API . For mange vil det altså være rimeligere å ta i bruk en slik standard tjeneste fremfor å utvikle egen maskinlæringsmodell.\nEt sikkert sted for gamle data Er du redd for at data fra et gammelt nedlagt system skal komme på avveie er OCI er trygt sted. Du styrer selv tilgang og kan hente det frem til ad-hoc analyse når du trenger det.\n","permalink":"https://enesi.no/no/2021/07/gratis-infrastruktur-med-oracle-free-tier/","summary":"\u003ch2 id=\"litt-sent-ute\"\u003eLitt sent ute\u003c/h2\u003e\n\u003cp\u003eBer du folk om å nevne skyleverandører kan de fleste innen IT ramse opp \u003cem\u003eAmazon Web Services\u003c/em\u003e (AWS), \u003cem\u003eAzure\u003c/em\u003e og \u003cem\u003eGoogle Cloud Platform\u003c/em\u003e (GCP). Forbausende mange har ikke hørt om \u003cem\u003eOracle Cloud\u003c/em\u003e, til tross for at Oracle database har hatt opp mot halvparten av det profesjonelle databasemarkedet.\u003c/p\u003e\n\u003cp\u003eDet kan være at Oracle Cloud lenge ikke var spesielt bra. Selv trofaste teknologer fra brukermiljøet til Oracle klagde høylytt om hvor vanskelig det var å komme i gang uten å betale dyrt, og at det var langt unna den modenhet og brukervennlighet som for eksempel AWS kunne tilby.\u003c/p\u003e","title":"Gratis infrastruktur med Oracle Free Tier"},{"content":" Du er gal!\n-- Asle, oktober 2020 Konsulent på egne ben Sitat over er fra en kamerat, uttalt rett etter at jeg hadde fortalt at jeg hadde sagt opp jobben for å begynne for meg selv. Prosessen som førte frem til avgjørelsen skrev jeg om i romjulen i Reboot Det som motiverer meg stadig vekk er at med relativt enkle metoder og litt tålmodighet kan man gjøre en stor forskjell for de som er avhengige av kritiske IT-systemer. Mange må slite med treg respons, upålitelighet, manglende funksjonalitet og så videre. Jeg ønsker å være der ute og grave ned i disse tingene, eller utvikle en ny løsning som kan erstatte noe som er mer til bry enn til hjelp. ITIL, PRINCE2 og virksomhetsarkitektur har sin plass i IT-landskapet, men jeg vil helst dra på tur et annet sted.\nTil tross for at jeg er litt introvert trives jeg å jobbe ute med kunder, enten alene i timesvis, eller i en prosjektgruppe. Nå sitter jeg riktignok som de fleste andre på hjemmekontor og jeg har aldri fått gjort så mye i løpet av en god arbeidsdag.\nEn uke er unnagjort og det ser lovende ut. I dag lagde jeg en oversikt på hva jeg kan bidra med, den finner du i Tjenester .\n","permalink":"https://enesi.no/no/2021/02/oppstart/","summary":"\u003cblockquote\u003e\n\u003cp\u003eDu er gal!\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv style=\"text-align: right\"\u003e \n-- Asle, oktober 2020\n \u003c/div\u003e\n\u003ch2 id=\"konsulent-på-egne-ben\"\u003eKonsulent på egne ben\u003c/h2\u003e\n\u003cp\u003eSitat over er fra en kamerat, uttalt rett etter at jeg hadde fortalt at jeg hadde sagt opp jobben for å begynne for meg selv. Prosessen som førte frem til avgjørelsen skrev jeg om i romjulen i \u003ca href=\"/2020/12/reboot\"\u003eReboot\u003c/a\u003e\n\u003c/p\u003e\n\u003cp\u003eDet som motiverer meg stadig vekk er at med relativt enkle metoder og litt tålmodighet kan man gjøre en stor forskjell for de som er avhengige av kritiske IT-systemer. Mange må slite med treg respons, upålitelighet, manglende funksjonalitet og så videre. Jeg ønsker å være der ute og grave ned i disse tingene, eller utvikle en ny løsning som kan erstatte noe som er  mer til bry enn til hjelp. ITIL, PRINCE2 og virksomhetsarkitektur har sin plass i IT-landskapet, men jeg vil helst dra på tur et annet sted.\u003c/p\u003e","title":"Oppstart"},{"content":"Dette er noen av tjenestene som tilbys på Oracle database og nærliggende teknologi\nOracle databaseadministrasjon (DBA) Optimalisering (tuning) av SQL og PL/SQL Feilsøking Oppgradering Migrering Til og fra sky Gamle versjoner Tilgjengeliggjøring av data i arkiverte/utfasede databaser Beredskap og kontinuitetsplanlegging Recovery Manager (RMAN) Data Guard Oracle opsjoner Spatial and Graph Oracle Text Machine Learning (tidligere Advanced Analytics) Partisjonering Advanced Compression Real Application Clusters (RAC) Real Application Testing In-Memory Multitenant Exadata Bedre utnyttelse i forhold til hyllevare (smart scan og annen offloading) Tilpasning for datavarehus Oppfølging av saker med Oracle Support Patching Sikkerhet Audit Autentisering Autorisering Kryptering av data - Transparent Data Encryption (TDE) Sikker arkitektur Oracle databaseutvikling SQL og PL/SQL Oracle APEX - full stack og low-code Datamodellering, revisjon av datamodell Bistand til utviklere: Bedre bruk av databasen: Beskrive hvordan Oracle jobber best Riktig konfigurasjon av JDBC og connection pool Gjennomgang av arkitektur og forslag til forbedringer DevOps i prosjekter Versjonskontroll og produksjonssetting av datamodell og kode Git Liquibase Flyway Endring av datamodell uten nedetid Løse skaleringsproblemer Databaseserver vs applikasjonsserver Testing: volum og funksjonell God og dårlig praksis Forvaltning av eldre systemer, videreutvikling og refactoring Verktøy: SQL Developer SQL Developer Data Modeler Oracle REST Data Services (ORDS) Dataanalyse Integrasjon av datakilder Apache Kafka REST API Tilpassede Bearbeiding av data for analyse Analyse med SQL, PL/SQL eller Python Datavarehus Materialized Views Stjernemodell ETL og ELT Oracle Machine Learning Riktig valg av algoritme Arbeidsflyt med Data Miner Rapportering / Presentasjon / visualsering I APEX REST API Generell infrastruktur Linux (Oracle Linux, Red Hat, Ubuntu, etc) Analyse av ytelse på Linux (CPU, I/O, minne) Virtualisering og lettvektsvirtualisering Oracle VM Virtual Box Vagrant Docker Automatisering - Infrastructure as code Ansible Terraform Overvåkning Prometheus Grafana Annen åpen kildekode ","permalink":"https://enesi.no/no/tjenester/","summary":"\u003cp\u003eDette er noen av tjenestene som tilbys på Oracle database og nærliggende teknologi\u003c/p\u003e\n\u003ch2 id=\"oracle-databaseadministrasjon-dba\"\u003eOracle databaseadministrasjon (DBA)\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eOptimalisering (\u003cem\u003etuning\u003c/em\u003e) av SQL og PL/SQL\u003c/li\u003e\n\u003cli\u003eFeilsøking\u003c/li\u003e\n\u003cli\u003eOppgradering\u003c/li\u003e\n\u003cli\u003eMigrering\n\u003cul\u003e\n\u003cli\u003eTil og fra sky\u003c/li\u003e\n\u003cli\u003eGamle versjoner\u003c/li\u003e\n\u003cli\u003eTilgjengeliggjøring av data i arkiverte/utfasede databaser\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eBeredskap og kontinuitetsplanlegging\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eRecovery Manager\u003c/em\u003e (RMAN)\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eData Guard\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eOracle opsjoner\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eSpatial and Graph\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eOracle Text\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eMachine Learning\u003c/em\u003e (tidligere \u003cem\u003eAdvanced Analytics\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003ePartisjonering\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAdvanced Compression\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eReal Application Clusters\u003c/em\u003e (RAC)\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eReal Application Testing\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eIn-Memory\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eMultitenant\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eExadata\n\u003cul\u003e\n\u003cli\u003eBedre utnyttelse i forhold til hyllevare (\u003cem\u003esmart scan\u003c/em\u003e og annen \u003cem\u003eoffloading\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003eTilpasning for datavarehus\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eOppfølging av saker med \u003cem\u003eOracle Support\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003ePatching\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eSikkerhet\n\u003cul\u003e\n\u003cli\u003eAudit\u003c/li\u003e\n\u003cli\u003eAutentisering\u003c/li\u003e\n\u003cli\u003eAutorisering\u003c/li\u003e\n\u003cli\u003eKryptering av data - \u003cem\u003eTransparent Data Encryption\u003c/em\u003e (TDE)\u003c/li\u003e\n\u003cli\u003eSikker arkitektur\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"oracle-databaseutvikling\"\u003eOracle databaseutvikling\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eSQL og PL/SQL\u003c/li\u003e\n\u003cli\u003eOracle APEX - \u003cem\u003efull stack\u003c/em\u003e og \u003cem\u003elow-code\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eDatamodellering, revisjon av datamodell\u003c/li\u003e\n\u003cli\u003eBistand til utviklere:\n\u003cul\u003e\n\u003cli\u003eBedre bruk av databasen: Beskrive hvordan Oracle jobber best\u003c/li\u003e\n\u003cli\u003eRiktig konfigurasjon av JDBC og \u003cem\u003econnection pool\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eGjennomgang av arkitektur og forslag til forbedringer\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eDevOps\u003c/em\u003e i prosjekter\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eVersjonskontroll og produksjonssetting av datamodell og kode\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eGit\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eLiquibase\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eFlyway\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eEndring av datamodell uten nedetid\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eLøse skaleringsproblemer\u003c/li\u003e\n\u003cli\u003eDatabaseserver vs applikasjonsserver\u003c/li\u003e\n\u003cli\u003eTesting: volum og funksjonell\u003c/li\u003e\n\u003cli\u003eGod og dårlig praksis\u003c/li\u003e\n\u003cli\u003eForvaltning av eldre systemer, videreutvikling og \u003cem\u003erefactoring\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eVerktøy:\n\u003cul\u003e\n\u003cli\u003eSQL Developer\u003c/li\u003e\n\u003cli\u003eSQL Developer Data Modeler\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eOracle REST Data Services\u003c/em\u003e (ORDS)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"dataanalyse\"\u003eDataanalyse\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eIntegrasjon av datakilder\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eApache Kafka\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eREST API\u003c/li\u003e\n\u003cli\u003eTilpassede\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eBearbeiding av data for analyse\u003c/li\u003e\n\u003cli\u003eAnalyse med SQL, PL/SQL eller Python\u003c/li\u003e\n\u003cli\u003eDatavarehus\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eMaterialized Views\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eStjernemodell\u003c/li\u003e\n\u003cli\u003eETL og ELT\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eOracle Machine Learning\n\u003cul\u003e\n\u003cli\u003eRiktig valg av algoritme\u003c/li\u003e\n\u003cli\u003eArbeidsflyt med \u003cem\u003eData Miner\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eRapportering / Presentasjon / visualsering\n\u003cul\u003e\n\u003cli\u003eI APEX\u003c/li\u003e\n\u003cli\u003eREST API\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"generell-infrastruktur\"\u003eGenerell infrastruktur\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eLinux (Oracle Linux, Red Hat, Ubuntu, etc)\u003c/li\u003e\n\u003cli\u003eAnalyse av ytelse på Linux (CPU, I/O, minne)\u003c/li\u003e\n\u003cli\u003eVirtualisering og lettvektsvirtualisering\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eOracle VM\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eVirtual Box\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eVagrant\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eDocker\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eAutomatisering - \u003cem\u003eInfrastructure as code\u003c/em\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eAnsible\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eTerraform\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eOvervåkning\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003ePrometheus\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eGrafana\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eAnnen åpen kildekode\u003c/li\u003e\n\u003c/ul\u003e","title":"Tjenester"},{"content":"Enesi Consulting AS er et spesialisert konsulentfirma eid og drevet av Øyvind Isene. Firmaet leverer ekspertise innen Oracle Database og relaterte teknologier, med fokus på ytelsesoptimalisering, stabil drift og teknisk rådgivning.\nØyvind Isene har over 25 års erfaring som databaseadministrator, arkitekt og rådgiver innen Oracle-teknologi. Han har bred kompetanse innen databaseadministrasjon, integrasjon, systemytelse, Linux, nettverk og automatisering. Gjennom hele karrieren har han hatt en særlig interesse for å forstå hvordan komplekse systemer oppfører seg – og hvordan de kan forbedres gjennom presis analyse og målrettet tuning.\nEnesi Consulting bistår kunder med alt fra feilsøking og ytelsesanalyse til design av robuste databasearkitekturer og migrering til moderne plattformer. Erfaringen spenner fra små og mellomstore virksomheter til store internasjonale miljøer med strenge krav til sikkerhet, tilgjengelighet og skalerbarhet. Mye av innholdet på nettsiden er på engelsk, ettersom prosjekter og samarbeid ofte foregår internasjonalt. Norske sider og artikler retter seg først og fremst mot tjenester og temaer som er spesielt relevante for kunder i Norge.\nOracle ACE Pro Symposium 42 Enesi Consulting AS Enesi Consulting AS\nKirkeveien 34\n4816 Kolbjørnsvik\nOrg.nr. 926 039 296 oyvind@enesi.no ","permalink":"https://enesi.no/no/about/","summary":"\u003cp\u003eEnesi Consulting AS er et spesialisert konsulentfirma eid og drevet av Øyvind Isene. Firmaet leverer ekspertise innen Oracle Database og relaterte teknologier, med fokus på ytelsesoptimalisering, stabil drift og teknisk rådgivning.\u003c/p\u003e\n\u003cp\u003eØyvind Isene har over 25 års erfaring som databaseadministrator, arkitekt og rådgiver innen Oracle-teknologi. Han har bred kompetanse innen databaseadministrasjon, integrasjon, systemytelse, Linux, nettverk og automatisering. Gjennom hele karrieren har han hatt en særlig interesse for å forstå hvordan komplekse systemer oppfører seg – og hvordan de kan forbedres gjennom presis analyse og målrettet tuning.\u003c/p\u003e","title":"Om Enesi Consulting"}]