We’ve got an exciting new feature to announce in 4D v18 and the title may have already given you a hint!
This feature opens new possibilities for client/server work. Rather than being limited to the current database and requiring a permanent network connection, an application in 4D v18 can get data from another, remote 4D database that’s exposed on a 4D server!
A lot of options become available thanks to this feature. For example, you could organize your applications to work offline and only synchronize local data when remote data is reachable. Or you could consider publishing your data on multiple servers and switching from one to the other as necessary. Another option could be splitting your data model across different databases (e.g. local data, international data). What about having your data distributed in different places yet still accessible through a single 4D client code (project methods and form objects)? All of these scenarios are now possible and this blog post tells you how!
HDI: How to work with a remote datastore
With 4D v18, your 4D database can be exposed as a REST server for other 4D client applications. This means that a 4D client can interact with the data you’ve exposed (create, read, update, delete). And even more good news: this interaction is based on ORDA concepts, so it’s completely object-oriented!
how to Expose your 4D database for remote access?
In the database Web settings:
- On the Configuration tab, configure an HTTP port (for security reasons, be sure to use HTTPS for production mode!)
- On the REST resource tab, select the “Expose as REST Server” option
- Start the Web server. In the example above, we chose to start the server at database startup.
- Open your database on the 4D Server.
- Congratulations! Your database is now reachable for remote access through your machine’s IP and the port you configured!
Note: Using the Web Server to access the REST Server does not require a Web Server license. Standard 4D Client licenses are used for connections.
Working with remote databases
Open datastore command
As we stated earlier, your database is reachable via ORDA concepts: a database is handled with a datastore object. Therefore, the first step is to get the datastore object corresponding to the remote database you want to access. No problem! Call the Open datastore command with the correct hostname and you’re off and running.
We associate the datastore object to the local ID, “students”. We can now start working with our remote database using ORDA (run queries, load/update entities, etc.)
C_OBJECT($connectTo;$schoolDS;$s)
C_TEXT($dataClass)
//The database contains a Students dataclass
$dataClass:="Students"
$connectTo:=New object("hostname";"school.acme.com")
$schoolDS:=Open datastore($connectTo;"students") //local id of this remote datastore is "students"
//Start working with ORDA means
ALERT("They are "+String($schoolDS[$dataClass].all().length)+" students")
//Run an ORDA query on the Students dataclass
$s:=$schoolDS[$dataClass].query("lastname=:1";"Smith").first()
If ($s#Null)
ALERT("Student "+$s.lastname+" lives in "+$s.address.city)
End if
Check the Open datastore documentation to learn more about how you can access a remote datatabase with a secured connection (TLS).
using multiple remote databases
Here’s a short example showing how easy it is to work with multiple remote databases. We have two databases: one contains French students, the other contains English students.
We can choose to view either French or English students.
The form method:
Case of
: (FORM Event.code=On Load)
Form.frenchServer:="french.acme.com"
Form.englishServer:="english.acme.com"
End case
The object method behind the “View French students” radio button:
C_OBJECT($connectTo;$students)
$connectTo:=New object()
$connectTo.hostname:=Form.frenchServer
$students:=Open datastore($connectTo;"french") //datastore containing French students
Form.students:=$students.Students.all()
The object method behind the “View English students” radio button:
C_OBJECT($connectTo;$students)
$connectTo:=New object()
$connectTo.hostname:=Form.englishServer
$students:=Open datastore($connectTo;"english") //datastore containing English students
Form.students:=$students.Students.all()
Note: The first time the Open datastore command is called, the datastore object is loaded in memory and a session is opened on the server. On subsequent calls it simply returns a reference on this datastore object.
control access to your remote database
To to keep the 4D database you’ve exposed safe, you can filter access to it. Let’s take another look at the Open datastore command. As shown below, it can be passed a user and a password.
C_OBJECT($connectTo;$myStudents)
ON ERR CALL("manageErrors")
$connectTo:=New object()
$connectTo.hostname:="students.acme.com"
$connectTo.user:="mary@4d.com"
$connectTo.password:=Form.password
//local id of this remote datastore is "students"
$myStudents:=Open datastore($connectTo;"students")
ON ERR CALL("")
4D provides two ways to restrict access to authorized users:
Use a 4D users group
Acces can be restricted using a 4D users group. When you expose the database, select the group allowed access on the Web settings page’s REST resource tab.
If the user given in the Open datastore command belongs to the selected group, access is granted, otherwise an authentication error is generated.
Use the on rest authentication database method
You can also use the new On REST authentication database method to code your own access control to the database you’ve exposed. This method receives the user’s credentials in the Open datastore command. Simply return True if the user is allowed to work with your remote database.
Here’s an example:
C_TEXT($1;$name;$2;$password)
C_BOOLEAN($0;$result;$3;$digest)
C_OBJECT($user)
$name:=$1 // The user to provide in Open datastore command
$password:=$2 // The password to provide in Open datastore command
$digest:=$3 // True if password is hashed
$result:=False
//Search for the user in our Users dataclass
$user:=ds.Users.query("name=:1";$name).first()
If ($user#Null)
// Passwords are hashed in Users dataclass
If ($digest & ($user.password=$password))
$result:=True
End if
End if
$0:=$result
Note: Theds and datastore.getInfo() commands have been updated, and three new methods were added: datastore.startTransaction(), datastore.cancelTransaction(), and datastore.validateTransaction().
Now it’s time to download the above HDI to learn more about this amazing feature!