B4J Tutorial Web API Server (v3)

Introduction
This tutorial is based on [Project Template] Web API Server 3.

Installation
  1. Download and save Web API Server (3.00).b4xtemplate file into B4J Additional Libraries folder.
  2. You also need to download WebApiUtils.b4xlib (v3.02) and save inside the same folder.
  3. It is recommended to use this template with MiniORMUtils.b4xlib (v1.14) which is a dependency by default.
    You can put this library inside B4X Additional Libraries folder since it is a cross platform library.
    Note: You can also use MinimaListUtils library or write your own SQL code using jSQL library.
  4. By default the template is based on SQLite database as backend.
    Therefore you need sqlite-jdbc driver in your B4J or B4X Additional Libraries folder. B4J comes with sqlite-jdbc-3.7.2 as Internal Library.
  5. If you want to use MySQL database, you need to use MySQL jdbc driver and put inside B4J Additional Libraries folder. e.g mysql-connector-java-5.1.49
Create Project
  1. Once all the required libraries and template are in place, you can start B4J IDE.
  2. Select from File menu, New, Web API Server (3.x)
  3. Enter the name of your project as you like. Then click OK.
  4. Now the project is ready to run as it is.
Running the Project
  1. Click menu Project, Compile & Run (F5) or the play button on the toolbar.
  2. Hover you mouse pointer to the AppStart sub and click on the highlighted link to open the app on your web browser.
  3. The browser will open and load the index page.
    It is a CRUD web application where you can add a new product (C), search for a product (R), edit an existing product (U) and delete a product (D).
  4. It has already generated some common APIs following the RESTful API principal.
    To see the list of APIs, click the API link with a gear icon on top navigation bar.
  5. You will be redirected to the API documentation page.
    You will see there are endpoints such as GET, POST, PUT and DELETE which are represented in different colours.
  6. You can click on any item to expand the section.
Perform Tests

GET
  1. Let's try to perform our first GET request with an id parameter.
    Click on the second end point labeled GET /api/categories/:id
  2. Edit the Path by replacing the :id parameter with 2 and click on the green Submit button.
  3. The form will send an AJAX request to the API server and return a JSON response (Code 200 for Success).
POST
  1. To test a POST end point, click the third item with labeled POST /api/categories.
    Copy the sample format from the left and paste in the Body textarea.
  2. Edit the content, i.e value of the category name in the illustration and click the yellow Submit button.
  3. You may follow the convention to return code 201 Created for new item added to the resource.
    For this demo, it is set to return a simple response and it doesn't support text Created but display success as default text.
    You need to set Simple Response to False in server configuration to return code 201 response for your client apps.
This is the end of tutorial for now. Thanks for taking your time to read it.

I will update this tutorial again from time to time.

Please do not post any question on this thread.

Always start a new question with the name Web API Server 3 or post your question here : [Q&A] Web Api Server 3
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #2: Configure Settings
  1. B4J generate a config.ini when you compile the project for the first time in Debug (or Release) mode.
  2. You can open the file using Notepad or any Text Editor.
  3. After you made any changes, you need to compile the project again for the settings to take effect.
B4X:
# Define App Constants
HOME_TITLE=WEB API SERVER
APP_TITLE=Web API Server
APP_TRADEMARK=B4X
APP_COPYRIGHT=Copyright Computerise System Solutions 2024
  1. You can edit these settings.
  2. It will applies to the text displayed on the front-end and API documentation page.
  3. Similar to config.properties, the values does not support UTF8. You may want to set text for non-English characters in the code.
B4X:
# Server Path
ROOT_URL=http://127.0.0.1
ROOT_PATH=
API_NAME=api
API_VERSIONING=False
  1. ROOT_URL (default=http://127.0.0.1) is for setting the server URL. You can edit to your domain name in production release.
    Note: It seems Chrome is no longer allowed http://localhost so it is better to stick with http://127.0.0.1 during development.
  2. ROOT_PATH (default=<empty>) can be set to other name e.g /web
  3. API_NAME (default=api) is better to leave as default. You need to change the values in code, html templates and JavaScript files if you edit it.
  4. API_VERSIONING (default=False) can be set to e.g /v1 or /preprod
B4X:
# Java server port
ServerPort=8080
SSLPort=0
  1. It is important to set the correct number for B4J server port.
  2. Make sure the port number is not used by another service or blocked by the firewall.
  3. You can set the port e.g 80
  4. It is recommended to use SSL protocol in production. If SSLPort number is set to 0, SSL is disabled.
  5. You can set it to e.g 443
B4X:
# SSL Keystores
# Generate a keystore from Windows CMD
# C:\Java\jdk-11.0.1\bin\keytool -keystore keystore -alias jetty -genkey -keyalg RSA
# Copy keystore file to Objects folder of the B4J project
SSL_KEYSTORE_DIR=/etc/letsencrypt/live/mydomain.com
SSL_KEYSTORE_FILE=keystore
SSL_KEYSTORE_PASSWORD=xxxxxxxxx
  1. If SSLPort is not set to 0 (enabled), you need to set the keystore settings.
  2. During development, you can use CMD to call keytool in the JDK to generate a self sign keystore file.
  3. Put this file in Objects folder and leave the SSL_KEYSTORE_DIR setting as <empty>.
  4. During production, you can use a real certificate or generate one using LetsEncrypt.
B4X:
# DATABASE CONFIGURATION

## SQLite configuration:
DbType=SQLite
DbFile=webapi3.db
DbDir=
DriverClass=org.sqlite.JDBC
JdbcUrl=jdbc:sqlite:{DbDir}/{DbFile}
  1. SQLite is set as default DbType.
  2. You can change the DbFile as you like e.g server.sqlite
  3. You can leave DbDir as <empty> to store the file inside Objects directory.
  4. If you want to save the file in a different location, you need to set it using forward slash or escape character e.g C:/server/db or C:\\server\\db
  5. It is recommended to leave the values for DbType, DriverClass and JdbcUrl as default.
  6. If you want to use MySQL as backend database, uncomment the settings like the following example.
    B4X:
    ## MySQL configuration:
    DbType=MySQL
    DbName=webapi3
    DbHost=localhost
    DbPort=
    DriverClass=com.mysql.cj.jdbc.Driver
    JdbcUrl=jdbc:mysql://{DbHost}:{DbPort}/{DbName}?characterEncoding=utf8&useSSL=false
    User=root
    Password=password
    MaxPoolSize=100
  7. You can leave DbPort as <empty> if MySQL is running on default port 3306.
  8. You can edit the DbName, User, Password, MaxPoolSize or other settings according to your needs.
This is the end of tutorial for Part #2. Thanks for taking your time to read it.

Always start a new question with the name Web API Server 3 if you have any question on this tutorial.
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #3: How Does the Project Work?
  1. First thing to know, this is a B4J server app. Therefore, it depends on the B4J Server library.
  2. You also need to understand, it is a non-UI or console app. It doesn't have native UI library or component.
  3. You can't add any B4J library that depends on XUI or jFX.
  4. After the project is compiled as Release, you can run the binary file on Windows CMD or Terminal on Linux.
  5. To host the server app, it is recommended to find a VPS that you have full access to run the binary using a remote SSH terminal.
  6. You also need to have a JDK on the server for you to call the .jar file.
  7. It is recommended that you put the compiled binary file e.g server.jar, together with the www directory inside a location that you have write permission.
  8. The server will have to write it's access log and database file if you are using SQLite to keep inside the location same as the binary file.
  9. You also need to make sure the server can read the config.ini file and contents inside www directory.
  10. You can follow the tutorials on this forum about running B4J Server.
Starting the Server
  1. To start the server, you Initialize the object as global in Main module and call the method Start.
  2. We should configure the settings before we start the server.
  3. The default server port number for B4J server is 8080.
  4. We can change this setting using InitServer sub in the Main module.
Initializing Server Configuration
  1. In this project, we use config.ini to make changes to the server configuration without needing to recompile the project.
  2. The settings in config.ini has been explained in the previous tutorial.
  3. This project has embedded with a config.example file in the assets or Files directory.
  4. If you have deleted the config.ini file, a new config.ini file will be copied from the example template.
  5. InitServer sub will read config.ini file for the configuration settings.
  6. All the configuration will be assigned to a Map object name ctx where it can be read from anywhere of the project and also use by HTML template engine, such as for displaying the title label and version number.
EnableCORS​
  1. This setting must be enabled to allow another application (from different origin) to access our API especially when using JavaScript.
  2. If you have another web app hosted with different port number e.g Vue app running on port 3000 and this server is running on port 8000 then you need to enable CORS or otherwise you will get errors in web browser.
  3. You can disable this setting if you are sure there are no other application sharing the API.
  4. This is not applied to mobile or desktop native client apps want to access the API.
EnableSSL​
  1. This setting is recommended to be set to True during production to protect the data transfer being encrypted between the server and client.
  2. As explained in previous tutorial, you need to configure the SSLPort to number other than 0 and provide information of the keystore.
EnableHelp​
  1. Basically this setting is use to hide the API documentation link to be visible to the end user.
  2. You can also use Conditional symbol to add or disable the HelpHandler during production.
SimpleResponse​
  1. This setting allows you to choose the API output in different JSON format.
  2. By default, it is not enabled.
  3. This means the output of the JSON Response follows a predefined the structure as set inside ReturnHttpResponse sub of WebApiUtils library.
  4. Learn more about SimpleResponse in tutorial part #5.
StaticFilesFolder​
  1. Usually the static files folder is set as www inside Objects during development.
  2. It is recommended to leave the folder name as www or you may want to change as public.
  3. After compiled as Release, it will become the same level as the jar file.
StaticFilesBrowsable​
  1. You may want to restrict the client to list the contents of your www assets directory from the browser.
  2. You can set StaticFilesBrowsable to False which is by default also set as False.
    B4X:
    Config.StaticFilesFolder = File.Combine(File.DirApp, "www")
    Config.StaticFilesBrowsable = False
Version​
  1. The VERSION_NAME is set in Process_Globals which is just for displaying purpose in front end and terminal log as "welcome message".
    B4X:
    Config.Version = VERSION_NAME
Applying Server Configuration
  1. The ApplySettings sub will take care of applying the settings if you have override any inside InitServer sub.
  2. You must not modify any code inside ApplySettings sub.
Initializing Database Configuration
  1. The InitDatabase sub will take care of applying the settings read from the config.ini file.
  2. You must not modify any code inside InitDatabase sub.
Connecting to the Database
  1. Based on the Build Configuration that you selected, the project is connecting to SQLite by default.
  2. You need to select MySQL from the dropdown list if you want to use MySQL database.
  3. CreateConnection sub will take care of applying the settings and attempt to connect to the database.
  4. It will also check if database is exist or else call CreateDatabase sub.
Creating the Demo Database
  1. If no database is present, the CreateDatabase sub will create a new database, generate the tables and insert some dummy data.
  2. As this template is using MiniORMUtils library, the same code is use to accomplish this task, regardless of whether you choose SQLite or MySQL.
  3. The SQL queries are handled internally by the library despite the differences between the 2 databases.
  4. You may want to learn about using MiniORMUtils in another tutorial or post a new question on this library.
Configure Cross Origin (CORS)
  1. If you have set Config.EnableCORS = True, then you may want to configure the Cross Origin settings on this server accessed from another origin or server inside the ConfigureCORS sub.
  2. This is the case when you have another application that is using JavaScripts to make API calls to this server.
  3. By default, there is already an example added for you.
    B4X:
    Paths.Add(CreateMap("path": "/api/*", "origins": "http://localhost, http://127.0.0.1:3000", "methods": "POST,PUT,DELETE", "headers": "*"))
  4. This mean you are allowing another application specified in the list of "origins" to access our /api "path" and its derivatives using the "methods" POST, PUT and DELETE.
Configure SSL for the Server
  1. The ConfigureSSL sub will take care of setting up the SSL. You must not change any code in this sub.
  2. This sub will display some messages in the Logs depending on the settings for EnableSSL and the settings in config.ini file.
Configure Static Files
  1. The ConfigureStaticFiles sub will take care of setting up the directory name and browse permission of static file folder. You must not change any code in this sub.
Switching of Database
  1. If you have decided to switch to another database by selecting a different item from the Build Configurations dropdown list, make sure you have commented the SQLite configuration explained in the previous tutorial Part #2.
  2. If the configuration does not match, the ShowBuildConfigurationNotMatch sub will display a warning message and the application will be terminated immediately.
Commonly Use Subs
  1. You can add extra subs to the Main module so they are reusable in any of the server handler classes.
  2. There are 3 subs added for you for communicating with the database.
  3. Note that DBConnector is part of the MiniORMUtils library.
    B4X:
    Public Sub DBEngine As String
        Return DBConnector.DBEngine
    End Sub
    
    Public Sub DBOpen As SQL
        Return DBConnector.DBOpen
    End Sub
    
    Public Sub DBClose
        DBConnector.DBClose
    End Sub
This is the end of tutorial for Part #3. Thanks for taking your time to read it.

Always start a new question with the name Web API Server 3 if you have any question on this tutorial.
 

Attachments

  • 1730309168209.png
    39.5 KB · Views: 33
  • 1730311132287.png
    102.4 KB · Views: 30
  • 1730311514459.png
    47.1 KB · Views: 28
  • 1730312251236.png
    24.4 KB · Views: 28
  • 1730313337189.png
    56.4 KB · Views: 24
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #4: Server Handlers

There are 4 types of Class for writing code in B4J.
  • Standard Class
  • Server Filter
  • Server Handler
  • Server WebSocket
In this tutorial, we will focus on Server Handler.
This is the class that we use most of the time to write all of the business logic for the API.

Conventions
  1. For this Web API Server template, we use the following naming convention to differentiate the purpose of the handler class.
    • Api Handler - to read the Request from the URI contains the path /api and output the Response as JSON
    • Web Handler - to read the Request from the URI without the /api path and output the Response as HTML
  2. For e.g there are 2 handlers for Categories i.e CategoriesApiHandler and CategoriesWebHandler.
  3. You can either have Api handler and/or Web handler.
  4. As you can guess, CategoriesApiHandler is use for taking care of the API endpoints for Categories while CategoriesWebHandler is use to display the web page to manage the Categories.
  5. IndexWebHandler is use to display the index page when a user browse to the root path.
  6. The index page calls the API endpoints from ProductsApiHandler and FindApiHandler.
  7. HelpHandler is use to display the API documentation page. It will be use to call any API endpoint that you have created.
  8. Each Web handler is linked to its respective JavaScript file to make AJAX calls and process the returned JSON Response from an Api handler.

To be continued...
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #5: SimpleResponse

SimpleResponse.Enable = False

  1. By default, a predefined structure is return when using ReturnHttpResponse sub of WebApiUtils to output the JSON response.
  2. I recommend to use the default because it covers the response status code, message and error message without the need to worry whether the response should be an array or object. The response data is always returned as an array (list).
    Here is an example of the output:
    JSON:
    {
      "a": 200,
      "r": [
        {
          "deleted_date": null,
          "category_id": 2,
          "id": 3,
          "product_price": 1000,
          "created_date": "2024-10-30 08:33:13",
          "product_code": "T002",
          "modified_date": null,
          "product_name": "Optimus Prime"
        }
      ],
      "s": "ok",
      "e": null,
      "m": "Success"
    }
  3. You won't notice this format in API documentation because only the response 'r' item is show. A small label is display below the response box results from the combination of 'a' and 'm' / 'e' items.
  4. For details, you can check the JavaScript code of help.js file inside scripts folder of www/assets.
    JavaScript:
    success: function (data) {
        if (data.s == "ok" || data.s == "success") {
            var content = JSON.stringify(data.r, undefined, 2)
            $("#response" + id).val(content)
            $("#alert" + id).html(data.a + ' ' + data.m)
            $("#alert" + id).removeClass("alert-danger")
            $("#alert" + id).addClass("alert-success")
            $("#alert" + id).fadeIn()
        }
        else {
            var content = JSON.stringify(data.r, undefined, 2)
            $("#response" + id).val(content)
            $("#alert" + id).html(data.a + ' ' + data.e)
            $("#alert" + id).removeClass("alert-success")
            $("#alert" + id).addClass("alert-danger")
            $("#alert" + id).fadeIn()
        }
    }
SimpleResponse.Enable = True
  1. You will notice in this version, the setting is set to True inside the code.
    B4X:
    Config.SimpleResponse.Enable = True
    Note: You can comment the code if you want.
  2. This is the case where you want to create API that follow the structure you want.
  3. When this setting is set to True, the JSON format as showed above is now show with just the 'r' part, exactly as what you see in the Response text area in API documentation page.
    JSON:
    {
        "deleted_date": null,
        "category_id": 2,
        "id": 3,
        "product_price": 1000,
        "created_date": "2024-10-30 08:33:13",
        "product_code": "T002",
        "modified_date": null,
        "product_name": "Optimus Prime"
    }
  4. You can actually compare the difference by viewing the actual output by pasting the API end point to the browser address.
    Take note that you can only see the output for GET request in browser.
Debugging using Developer Tools
  1. We can use the Developer Tool in web browser for debugging the API response.
  2. First we need to write console.log() inside the JavaScript for AJAX call.
  3. This is useful for debugging other methods such as POST, PUT and DELETE.
  4. When Config.SimpleResponse.Enable = True, the response is in simple format.
  5. The page for API documentation will load help.simple.js file to make AJAX calls.
  6. Open help.simple.js using a Text Editor and add the following code at line #88.
    console.log(data)
  7. The code will look like the following:
    JavaScript:
    case element.hasClass("get"):
        return {
            type: "GET",
            headers: headers,
            success: function (data, textStatus, xhr) {
                console.log(data)
                var content = JSON.stringify(data, undefined, 2)
                $("#response" + id).val(content)
                $("#alert" + id).html(xhr.status + ' ' + textStatus)
                $("#alert" + id).removeClass("alert-danger")
                $("#alert" + id).addClass("alert-success")
                $("#alert" + id).fadeIn()
            },
            error: function (xhr, textStatus, errorThrown) {
                var content = xhr.responseText
                $("#response" + id).val(content)
                $("#alert" + id).html(xhr.status + ' ' + errorThrown)
                $("#alert" + id).removeClass("alert-success")
                $("#alert" + id).addClass("alert-danger")
                $("#alert" + id).fadeIn()
            }
        }
        break
  8. After changes is saved, you need to refresh the JavaScript source by right clicking on the page and choose view page source (Ctrl+U).
    Scroll down to the bottom of the page until you see
    <script src="http://127.0.0.1:8080/assets/scripts/help.simple.js"></script>
  9. Click on the link to open it on a new tab and right-click Reload (Ctrl+R).
  10. Open the Dev Tools by right clicking on the page (on Google Chrome) and choose Inspect (usually you need to scroll to bottom of the pop up menu) or just press combo keys of Ctrl+Shift+I.
  11. The Dev Tools panel will appear. Usually it is focusing on the Console tab. Otherwise you need to click on the Console tab.
  12. Now try to make a new GET request.
    You should see an arrow with text Object appeared and on the left showing 1 user message.
    On the right you see the name of the JavaScript file colon the line number on the code that produce the message log.
  13. Click the Object to expand it. You can see the content of the JSON object return from the API.
  14. If it is not working, probably you need to restart the server. Stop the debug and click run again. Then try again.
  15. The default JSON Format for SimpleResponse is "Auto".
    You can change the Format by setting it to "Map" to return as object (or "List" to return as array) for all the API responses.
    View attachment 158142
  16. By changing it to Map, you need to specify the key of the "Map" using the DataKey property.
    If you don't specify a key name, it will use "data" as the default key.
    B4X:
    Config.SimpleResponse.Initialize
    Config.SimpleResponse.Enable = True
    Config.SimpleResponse.Format = "Map"
    Config.SimpleResponse.DataKey = "result"
  17. After made this changes, now try to restart the debug (F11) and see the difference of output but this time we test on the API end point that should return an array (list) which is the /api/products end point.
  18. So you see the response is now return as object (wrapped in curly brackets) instead as an array (wrapped in square brackets) and it is using the key that we specified.
Conclusion
  1. There are 4 types of output for SimpleResponse:
    SimpleResponse.Enable =False|Format=(Fixed)|Return data=object with r data always an array
    SimpleResponse.Enable =True|Format=Auto (default)|Return data=depends whether we initialize object or data
    SimpleResponse.Enable =True|Format=Map|Return data=always as object (with optional customize key name)
    SimpleResponse.Enable =True|Format=List|Return data=always as array
  2. It depends on your use case which type is suitable.
  3. You can build more complex JSON response by nesting the objects and arrays.
This is the end of tutorial for Part #5. Thanks for taking your time to read it.

Always start a new question with the name Web API Server 3 if you have any question on this tutorial.
 
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…