Giter VIP home page Giter VIP logo

amforeas's Introduction

Amforeas

The Greek word for ‘amphora’, a type of container usually found on ancient ships.

Build

A RESTful Interface to your database

Amforeas is a server which allows CRUD operations over any of the supported RDBMS using REST.

By using REST, different CRUD operations are performed by different HTTP methods:

  • POST to create a resource
  • GET to read a resource
  • PUT to update a resource
  • DELETE to delete a resource
  • HEAD to describe a resource

Where a resources is a table or a view.

Amforeas is based on the premise that you love your database, hence there's no administration. If there's something missing in Amforeas, it probably means you have to do it in your database (roles, triggers, stored procedures, views, etc.) or build a more suitable backend solution.

Features

You can

  • Deploy in the cloud.
  • Run as a standalone server.
  • Deploy in your favorite JEE application server (Wildfly, Tomcat, Glassfish).

Usages

This are some projects where Amforeas is ideal:

  • Microservices access to data.
  • JavaScript applications without any server-side coding (React, Angular, AJAX).
  • Python, Perl and Bash scripts without any database driver.
  • ETL & KPIs.
  • Data-warehousing.
  • Cron jobs.
  • Provide restricted access to a database server.
  • Stubs server.

Currently supported databases

  • PostgreSQL
  • MySQL/MariaDB
  • Derby
  • HSQLDB (in-memory & file)
  • H2 (in-memory, file & remote)
  • MSSQL
  • Oracle

Future

  • JWT authorization
  • More RDBMS dialects
  • NoSQL database dialects
  • First Level Cache
  • GraphQL

Installation

For installation instructions check the Wiki


Examples

This examples are from data when running Amforeas with a demo application.

Read (GET) a resource

To read (GET) a user with id 1 from its table, we perform the following:

$curl -i -X GET -H "Accept: application/json" "http://localhost:8080/amforeas/demo1/user/1"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:23:48.470+02:00
Content-Count: 1
Content-Location: user
Content-MD5: uLcUX7L3SZknHpLvhUkERg==
Content-Length: 143
{
   "success":true,
   "cells":[
      {
         "birthday":"1992-01-15",
         "credit":"0.00",
         "lastupdate":"2012-03-27T14:23:48.466+02:00",
         "name":"bar",
         "age":33,
         "id":1
      }
   ]
}

This is the full HTTP with its header and body. As you can see, we asked in the HTTP request header Accept: application/json for a JSON representation of the user entity with id 1 in the database/schema demo1.

By default, Amforeas uses JSON as the transport format, but you can also use XML by simply changing the Accept header:

$ curl -i -X GET -H "Accept: application/xml" "http://localhost:8080/amforeas/demo1/user/1"
HTTP/1.1 200 OK
Content-Type: application/xml
Date: 2012-03-26T23:31:06.110+02:00
Content-Count: 1
Content-Location: user
Content-MD5: eOsCCV/1/zkXhxKIRMV4ug==
Content-Length: 261
<response>
  <success>true</success>
  <resource>user</resource>
  <rows>
    <row roi="0">
      <columns>
        <birthday>1992-01-15</birthday>
        <credit>45.00</credit>
        <lastupdate>2012-03-27T14:31:06.110+02:00</lastupdate>
        <name>foo user</name>
        <age>30</age>
        <id>1</id>
      </columns>
    </row>
  </rows>
</response>

If the resource doesn't exists, you'll get a 404

$ curl -i -X GET -H "Accept: application/json" "http://localhost:8080/amforeas/demo1/user/2"
HTTP/1.1 404 Not Found
Content-Type: application/json
Date: 2012-03-26T23:37:54.100+02:00
Content-MD5: 0+WJ/rKID3SXLnjerbee1g==
Content-Length: 39
Content-Length: 39
Content-Location: user
{"success":false,"message":"Not Found"}

Depending on RDBMS support, SQL errors will be mapped to HTTP errors.


Create (POST) a resource

To insert (POST) a new registry in the user table, we perform the following:

$curl -i -X POST -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"my foo user", "age":30, "credit":45.0}' \
  "http://localhost:8080/amforeas/demo1/user"
HTTP/1.1 201 Created
Content-Type: application/json
Date: 2012-03-26T23:29:17.125+02:00
Content-Count: 1
Content-MD5: eLzHpBV+Q6y46F/teUejMA==
Content-Length: 30
{"success":true,"cells":[ {}]}

The HTTP response code changed to 201 (Created) which means the entity was created successfully.


Update (PUT) a resource

You can also update values by providing a PUT request with the ID and the columns/values.

$ curl -i -X PUT -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"im updated!", "age":40}' \
  "http://localhost:8080/amforeas/demo1/user/3"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:36:14.299+02:00
Content-Count: 1
Content-Location: user
Content-MD5: dtt+NFNh9z5Ssh5ZYGt9yw==
Content-Length: 152
{
   "success":true,
   "cells":[
      {
         "birthday":"2012-03-27",
         "credit":"45.00",
         "lastupdate":"2012-03-27T14:36:14.299+02:00",
         "name":"im updated!",
         "age":40,
         "id":3
      }
   ]
}

Delete (DELETE) a resource

To delete you use a DELETE request with the ID in the table.

curl -i -X DELETE -H "Accept: application/json"  "http://localhost:8080/amforeas/demo1/user/2"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:37:20.803+02:00
Content-Count: 1
Content-Location: user
Content-MD5: eLzHpBV+Q6y46F/teUejMA==
Content-Length: 30
{"success":true,"cells":[ {}]}

Tables and meta

For Amforeas, everything after the amforeas/ path is an accessible resource, for example, the demo1 schema:

$ curl -i -X GET -H "Accept: application/json" "http://localhost:8080/amforeas/demo1"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:39:36.340+02:00
Content-Count: 8
Content-Location: demo1
Content-MD5: Fq5vDIHzxEYTBBeamLXbGQ==
Content-Length: 2337
{
   "success":true,
   "cells":[
      {
         "table_name":"USER",
         "type_cat":"null",
         "remarks":"null",
         "type_schem":"null",
         "hsqldb_type":"MEMORY",
         "commit_action":"null",
         "table_schem":"PUBLIC",
         "table_cat":"PUBLIC",
         "self_referencing_col_name":"null",
         "type_name":"null",
         "ref_generation":"null",
         "table_type":"TABLE",
         "read_only":"FALSE"
      }
   ]
}

If you ask for the database, its entities are returned. You can also query for a table's metadata with HEAD

$ curl -i -X HEAD -H "Accept: application/json" "http://localhost:8080/amforeas/demo1/user"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:42:15.254+02:00
Content-Location: user
User: ID=INTEGER(11);NAME=VARCHAR(25);AGE=INTEGER(11);BIRTHDAY=DATE(10);LASTUPDATE=TIMESTAMP(26);CREDIT=DECIMAL(8)
Content-MD5: dWYBu98TXrlGBjdvsDa8Gg==
Content-Length: 801

In this case, the HEAD response doesn't include any body, but your table metadata is included in a header with the name of it.


Querying

Apart of using GET requests, you can also use two more ways of querying

Calling functions or stored procedures

$ curl -i -X POST -H "Content-Type: application/json" -d '[{"value":2010, "name":"year", "outParameter":false, "type":"INTEGER", "index":1},{"name":"out_total", "outParameter":true, "type":"INTEGER", "index":2}]' "http://localhost:8080/amforeas/demo1/call/get_year_sales"
HTTP/1.1 200 OK
Content-Type: */*
Content-Count: 1
Content-Location: get_year_sales
Date: 2012-04-02T01:24:35.677+02:00
Content-MD5: mRewGokS4XVF1CEgjXrPxg==
Content-Length: 44
{"success":true,"cells":[ {"out_total":12}]}

As you can see, you call your stored procedure /amforeas/demo1/call/get_year_sales with a POST request, giving Amforeas the needed parameters in the request's body:

[
  {"value":2010, "name":"year", "outParameter":false, "type":"INTEGER", "index":1},
  {"name":"out_total", "outParameter":true, "type":"INTEGER", "index":2}
]

DynamicFinders inspired by Grails

$ curl -i -X GET -H "Accept: application/json" "http://localhost:8080/amforeas/demo1/user/dynamic/findAllByIdBetween?args=0&args=4"
HTTP/1.1 200 OK
Content-Type: application/json
Date: 2012-03-26T23:34:50.145+02:00
Content-Count: 4
Content-Location: user
Content-MD5: 3mTUmmN9ody68WB6/YXz7Q==
Content-Length: 507

Here we are telling Amforeas to find all demo1.user entities where id is between 0 and 4

{
   "success":true,
   "cells":[
      {
         "birthday":"1982-12-13",
         "credit":"32.50",
         "lastupdate":"2012-03-27T14:34:50.144+02:00",
         "name":"foo",
         "age":30,
         "id":0
      },{
         "birthday":"2012-03-27",
         "credit":"45.00",
         "lastupdate":"2012-03-27T14:34:50.145+02:00",
         "name":"my foo user",
         "age":30,
         "id":3
      }
   ]
}

Paging and sorting

Amforeas supports paging and sorting arguments when retrieving resources. Some responses from Amforeas include a pagination object which can be used for easy pagination:

$ curl "http://localhost:8080/amforeas/demo1/user/age/30?page=1&pageSize=50"
HTTP/1.1 200 OK
{
  "success":true,
  "status":"OK",
  "rows":[
  ],
  "resource":"users",
  "pagination":{
    "page":1,
    "size":50,
    "pages":4,
    "total":97
  }
}

To sort the data use the sort and dir parameters:

$ curl "http://localhost:8080/amforeas/demo1/user/age/30?page=1&pageSize=50&sort=age&dir=desc"
HTTP/1.1 200 OK

Date, Timestamp, Time

Amforeas uses JodaTime to handle all this conversions. Specifically, we use the ISODateTimeFormat. So if you want to communicate with Amforeas and read/write this data types, you must use the ISO format.

Date columns use the format yyyy-MM-dd as specified in the date() method.

Datetime columns use the format yyyy-MM-dd'T'HH:mm:ss.SSSZZ as specified in the dateTime() method.

Time columns use the format HH:mm:ss.SSSZZ as specified in the time() method.

For example, a user table with a birthday field of type DATE, and a lastupdate TIMESTAMP is returned as this:

{
  "birthday":"1982-12-13",
  "credit":"32.50",
  "lastupdate":"2011-12-12T22:19:14.931+01:00",
  "name":"foo",
  "age":30,
  "id":0
 }

Supported RDBMS

RDBMS Supported Tested
Mysql Yes Yes
Postgres Yes Yes
MSSQL Yes No
Oracle Yes Kind of
HSQLDB Yes Yes
H2 Yes Yes
Derby Yes Yes

Limitations

The following SQL types are not supported and will be ignored:

  • BLOB
  • ARRAY
  • BINARY
  • CLOB
  • STRUCT
  • VARBINARY
  • REF /REF_CURSOR
  • LONGVARBINARY
  • JAVA_OBJECT
  • DATALINK

Fields of numeric types will be transformed to numeric when possible. All other types will be transformed to strings.

Technology

RESTful

Neither REST nor RESTful webservices are a defined standard but The Atom Publishing Protocol gives a pretty good layout to conform to. Amforeas tries to follow the conventions on this document.

Java

Amforeas works as a stand alone server or daemon and uses the following open source projects:

  • Jetty 9
  • Jersey 2
  • Maven 3
  • Jakarta Commons DBUtils
  • Jakarta Commons DBCP
  • Jakarta Commons Lang
  • JAX-RS & Jackson
  • Logback
  • Joda Time
  • JUnit & Mockito

Changelog

amforeas's People

Contributors

dependabot[bot] avatar eldelshell avatar samarjit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

amforeas's Issues

Pagination support required

Reported by samarjit.samanta, Yesterday (17 hours ago)
What steps will reproduce the problem?

  1. Currently input can be there for limits and offset. But in the result the values are not reflected. It would be good to reflect the actual page no., actual number of records sent back, total records in the DB table at the time of query, offset and limit which were in input data.

What is the expected output? What do you see instead?

This type of data is available in query result then using it to create pagination grids will be more robust against quick varying tables data.

What version of the product are you using? On what operating system?

0.2 on windows 7, jdk 7.

Please provide any additional information below.

Also is it safe to use it directly in browser environment? as it exposes column names directly. I would rather build some kind of column lookup for safety from SQL injection. I know prepared statements will guard a lot against but still.

jongo.sh for MacOS

Provide an script or executable to run Jongo in a MacOSX environment as a standalone application or as a service.

Include JWT authorization

Analyze the chances of adding a JWT abstraction so requests are authorized from an external authentication service.

Allow named columns

Currently all request return all fields on the results (SELECT * FROM) like:

/amforeas/demo1/users/1
/amforeas/demo1/users/name/foo

We should allow the request to indicate the fields we want back (SELECT name,age):

/amforeas/demo1/users/1?fields=name,age
/amforeas/demo1/users/name/foo?fields=name

Return correct JSON types

Currently, JSON data is made of strings only:

"cells": {
  "birthday": "1991-01-15",
  "name": "bar5",
  "id": "5",
  "lastupdate": "2020-05-08T20:48:25.090+02:00",
  "credit": "0.00",
  "age": "20"
}

In this situation, age & credit should be numbers:

"cells": {
  "birthday": "1991-01-15",
  "name": "bar5",
  "id": "5",
  "lastupdate": "2020-05-08T20:48:25.090+02:00",
  "credit": 0.00,
  "age": 20
}

POSTing an array

I'm not totally sure about this, but we might accept an array of objects in a POST like:

[{"name":"foo","age":20},{"name":"bar","age":30}]

H2 database compatibility jongo.properties jdbc url

Hi,
I added H2 compatibility.
jongo-core/src/main/java/jongo/enums/JDBCDriver.java
jongo-core/src/main/java/jongo/sql/dialect/H2Dialect.java
jongo-core/src/main/java/jongo/config/DatabaseConfiguration.java
jongo-core/src/main/resources/jongo.properties

I also felt that having opportunity to control creation of JDBC URL in config file is a good option.

https://github.com/ubersoldat/jongo

As an admin, I want to set database access rules

Sometimes you won't have admin access to a database instance so allow database access rules to be applied on runtime.

For example, something like:

[{
  "alias1": {
       "users": {
         "allow": "all",
         "deny": "head, delete, post, get, put"
     }
  }
}]

Here we would have to add another file to the classpath or load it (like the JKS file) which means
that custom docker images would have to be created everytime a change is required (unless a volume is used...)

Or with properties, like a complemetely locked down database:

amforeas.alias1.jdbc.rules.deny=all
amforeas.alias1.jdbc.rules.catalog.allow=head, get
$ curl -X GET "http://.../amforeas/alias1/catalog/1" > 200
$ curl -X DELETE "http://.../amforeas/alias1/catalog/1" > 405 Method Not Allowed
$ curl -X GET "http://.../amforeas/alias1/foo/1" > 405 Method Not Allowed

Or a fine grained ACL:

amforeas.alias2.jdbc.rules.deny=none
amforeas.alias2.jdbc.rules.users.allow=head, get
amforeas.alias2.jdbc.rules.cars.allow=head, get, delete, post, put
amforeas.alias2.jdbc.rules.photos.allow=all
$ curl -X GET "http://.../amforeas/alias2/users/1" > 200
$ curl -X DELETE "http://.../amforeas/alias2/users/1" > 405 Method Not Allowed
$ curl -X GET "http://.../amforeas/alias1/bar/1" > 200

GAE support

Implement jongo-gae with support for App Engine Datastore

Add a way for JSON requests to specify the format

The idea is to allow different JSON formats which can be used with different REST clients.

The default format is:

{
  "success":true,
  "status":"OK",
  "rows":[
    {
      "roi":0,
      "cells":{
        "birthday":"1982-12-13",
        "name":"foo",
        "id":0,
        "lastupdate":"2020-05-08T21:17:21.993+02:00",
        "credit":32.50,
        "age":30
      }
    }
  ],
  "resource":"users",
  "pagination":{
    "page":1,
    "size":6,
    "pages":1,
    "total":6
  }
}

To allow this, we can either use:

  • a map JSON file set with configuration
  • During runtime with a POST endpoint which receives the format JSON data.
  • Allow GET endpoints to accept POST requests with the format JSON data.

The format data would look like:

{
  "formats": [
    {
      "resource": "users",
      "meta": {
        "success": true,
        "status": false,
        "pagination": true
      },
      "model": {
        "id": "number",
        "name": "string",
        "birthday": "dd/MM/yyyy",
        "credit": "number"
      }
    },{
      "resource": "cars",
      "meta": null,
      "model": {
        "id": "number",
        "maker": "string",
        "lastUpdate": "ddMMyyyyhhmmss"
      }
    }
  ]
}

A response from users then would be formatted as:

{
  "success":true,
  "pagination":{
    "page":1,
    "size":6,
    "pages":1,
    "total":6
  },
  "entities": [
    {
      "id":0,
      "name":"foo",
      "birthday":"13/12/1982",
      "credit":32.50
    }
  ]
}

And a response from cars (with no metadata) would look like:

{
  "id":0,
  "maker":"foo",
  "lastUpdate":"13121982040130"
}

Allow for specifying primary key (including composite ones) instead of hardcoding to `id`

I know https://github.com/Eldelshell/amforeas/wiki/Examples allows retrieving by other fields, but my MySQL database schema does not have an id field, so it bugs out:

$ curl -sL "http://127.0.0.1:8080/amforeas/db/tbl/fld/val" -H "Accept: application/json"
{"resource":"tbl","success":false,"status":"BAD_REQUEST","message":"Unknown column 't.id' in 'order clause' Query: SELECT t.* FROM tbl.fld t WHERE t.fld = ? ORDER BY t.id ASC LIMIT 0,25 Parameters: [val]","sqlState":"42S22","sqlCode":1054}

There also doesn't seem to be any provision for composite primary keys?

jongo.bat for Windows

Provide an script or executable to run Jongo in a Windows environment as a standalone application or as a service.

Extend ACLs to control columns

Since we're already configuring ACLs on the resource level, we can also add the option for an admin to limit the columns a client has access to.

amforeas.alias3.acl.rules.users.allow=read
amforeas.alias3.acl.rules.users.columns=id, email, name, age

This would affect inserts and updates, so non-defined (i.e. password in users) columns need to be nullable or any of these operations would fail.

We could also force that if the allow has any of all, insert or update rules, the columns property cannot be set. It would also be possible to show a warning:

Resource ${table} is limited to columns ${columns}. It's recommended the allow rule only applies "read" permissions or ignored columns are nullable.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.