B4J CouchDB client application using jShell with cURL command line tool and JSON documents.

PaulMeuris

Active Member
Licensed User
In this tutorial you can test a B4J application that connects to local CouchDB databases.
The command line tool cURL is used in this implementation to send command strings to the CouchDB server.
After the download, the installation and the setup of CouchDB you can use a webclient called Project Fauxton.
The webclient can be launched in a webbrowser with this local url: Fauxton. All the CouchDB documentation is available there.
This B4J application shows that you can use B4J code to maintain the information from CouchDB databases.
You can add, change or delete databases, documents, fields and attachments.
1690703668411.png

The jShell library is used to start cmd.exe that runs a cURL command.
The cURL tool is installed on the computer where CouchDB is installed. You can find examples of the curl commands in the CouchDB documentation.
The application consists of a B4Xpages module and a couchdb class module.
You can find the source code in the attached zip-file.
A user manual (couchdbclient.pdf) for the B4J application that contains installation instructions is also available in the attachments.
 

Attachments

  • couchdbclient.pdf
    458.7 KB · Views: 284
  • couchdbclient.zip
    13.7 KB · Views: 169

PaulMeuris

Active Member
Licensed User
Why use curl when we can use okhttputils2?
Because the examples with curl are available in the CouchDB documentation and you can test the commands in the command prompt window.
I tried okhttputils2 and got stuck on the error message from CouchDB: Response: {"error":"unauthorized","reason":"You are not a server admin."}
I did use the server admin credentials. I did not look into that much further.
Do you have an example laying around somewhere that uses okhttputils2 and the CouchDB server?
Here is an example that works with curl:
E:\couchdb_files>curl -X GET http://admin:admin@127.0.0.1:5984/_all_dbs
["_replicator","_users","albums"]
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
Hi

Awesome, I think most of us get stuck where we have to convert curl to httpUtils commands. This is awesome actually for anyone wanting to learn. Great work.

I found this link, it shows how the credentials are used.


My implementation is for web and uses Javascript though.


Thanks a lot for this, I will learn something from it Im sure.
 

aeric

Expert
Licensed User
Longtime User
B4X:
Private Sub Button1_Click
    Dim job As HttpJob
    job.Initialize("", Me)
    Try       
        job.Username = "admin"
        job.Password = "password"
        job.Download("http://localhost:5984/_all_dbs")
        Wait For (job) JobDone (job As HttpJob)
        If job.Success Then
            Log(job.GetString)
        Else
            Log(job.ErrorMessage)
        End If       
    Catch
        Log(LastException)
    End Try
    job.Release
End Sub

Logs:
B4X:
["_replicator","_users","albums"]
 

aeric

Expert
Licensed User
Longtime User
I have played with this project for a few minutes.
I install it without setting as Windows Service. Then I use cmd (as Administrator) to call couchdb.cmd (Ctrl+C to terminate).

In B4J client app, I changed the root drive so the output.json is saved inside the B4J Objects folder.

B4X:
Private rootdrive As String = File.DirApp
dirpath = File.Combine(rootdrive, "couchdb_files")


This reminds me of my MinimaList class which uses KVS.
INTRODUCING: MinimaList -> store as Map/List. API server can run without database (or optionally persist as KeyValueStore).

I also created a code snippet for Lettuce (Redis) which can be use for server cache or as NoSQL db.
 

PaulMeuris

Active Member
Licensed User
Thank you @aeric and @Mashiane for your replies.

The default security settings in the default.ini file in the folder e:\couchdb\etc can be modified:
;default_security = admin_only
; prevent non-admins from accessing /_all_dbs and /_dbs_info
;admin_only_all_dbs = true

Just a small observation when using jokhttputils2:
job.PostString sends a POST request and job.PutString sends a PUT request BUT job.GetString doesn't send a GET request.
If you need to use a GET request you have to use job.Download.
And of course you have to use the job.Username = "admin" and job.Password = "admin" to access the CouchDB database.
 

aeric

Expert
Licensed User
Longtime User
Thank you @aeric and @Mashiane for your replies.

The default security settings in the default.ini file in the folder e:\couchdb\etc can be modified:
;default_security = admin_only
; prevent non-admins from accessing /_all_dbs and /_dbs_info
;admin_only_all_dbs = true

Just a small observation when using jokhttputils2:
job.PostString sends a POST request and job.PutString sends a PUT request BUT job.GetString doesn't send a GET request.
If you need to use a GET request you have to use job.Download.
And of course you have to use the job.Username = "admin" and job.Password = "admin" to access the CouchDB database.
I think you are not familiar with okhttputils2. Indeed, to send GET request, you need to use job.Download and job.GetString is to get the result return from the server. I think the naming of the method may be due to conflicting with B4X or Java Get reserved keyword. Only Erel can answer. For GET and DELETE http verbs, we are not sending message body, unlike POST and PUT which expect the message body to be send with the request thus the methods name with postfix -String for content contains String. There are other method such as PostByte which expect raw bytes.
 

PaulMeuris

Active Member
Licensed User
The alternative to curl as suggested by @aeric:
Second couchdb class using okhttputils2:
Sub Class_Globals
    Private xui As XUI
    Private fx As JFX
    Public cdb2_user As String
    Public cdb2_password As String
    Public urlhead2 As String
End Sub
Public Sub Initialize(host As String, port As Int, user As String, password As String)
    cdb2_user = user
    cdb2_password = password
    urlhead2 = "http://" & host & ":" & port & "/"
End Sub
Public Sub send_request(reqtype As String,strurl As String,ctype As String,data As String) As ResumableSub
    Dim job As HttpJob
    job.Initialize("", Me)
    Dim strres As String = ""
    Try
        job.Username = cdb2_user
        job.Password = cdb2_password
        Select reqtype
            Case "DELETE"
                job.Delete(strurl)
            Case "GET"
                job.Download(strurl)
            Case "POST"
                job.PostString(strurl,data)
            Case "PUT"
                job.PutString(strurl,data)
                job.GetRequest.SetContentType(ctype)
        End Select
        Wait For (job) JobDone (job As HttpJob)
        If job.Success Then
            strres = job.GetString
        Else
            strres = job.ErrorMessage
        End If
    Catch
        Log(LastException)
    End Try
    job.Release
    Return strres
End Sub
And here's how you can use it in the subroutines of the B4XMainPage:
B4X:
' declaration
Public cdb2 As couchdb2
' initialization
cdb2.Initialize("127.0.0.1",5984,"admin","admin")

' get all databases
Wait For (cdb2.send_request("GET",cdb2.urlhead2 & "_all_dbs","","")) Complete (Result_alldbs As String)
Dim strres As String = Result_alldbs

'create new database
Wait For (cdb2.send_request("PUT",cdb2.urlhead2 & tfnewdb.text,"","")) Complete (Result_create As String)

' delete database
Wait For (cdb2.send_request("DELETE",cdb2.urlhead2 & dbname, "","")) Complete (Result_delete As String)

' get all documents
Wait For (cdb2.send_request("GET",cdb2.urlhead2 & dbname & "/_all_docs?include_docs=true","","")) Complete (Result_all_docs As String)
Dim strres As String = Result_all_docs

' get document
Wait For (cdb2.send_request("GET",cdb2.urlhead2 & dbname & "/" & id,"","")) Complete (Result_get_document As String)
Dim strres As String = Result_get_document

' add new document
Wait For (cdb2.send_request("PUT",cdb2.urlhead2 & dbname & "/" & id & "/","",strdata)) Complete (Result_add_document As String)

' update an existing document
Wait For (cdb2.send_request("PUT",cdb2.urlhead2 & dbname & "/" & id & "/?rev=" & lblrev.text,"",strdata)) Complete (Result_update_document As String)               

' delete a document
Wait For (cdb2.send_request("DELETE",cdb2.urlhead2 & lbldb.text & "/" & lbldoc.text & "/?rev=" & lblrev.text, "","")) Complete (Result_delete_document As String)

'add an image attachment
Wait For (cdb2.send_request("PUT",cdb2.urlhead2 & lbldb.text & "/" & lbldoc.text & _
    "/" & filename & "?rev=" & lblrev.text,"image/jpg","")) Complete (Result_add_image_attachment As String)
Remark: updating a document with attachments seems to be a challenge... "Bad special document member: _attachments" error... still searching for a solution...
 
Top