B4J Tutorial Pakai framework v5

Part #1: Get Started

Introduction

This tutorial is based on [Project Template] Pakai Server v5.

Installation

Option 1:

  1. Download and put the following files to Additional Libraries folder (don't put inside new subfolder)
    B4J:
    - Pakai Server (5.00).b4xtemplate
    - EndsMeet.b4xlib (v1.10)
    - WebApiUtils.b4xlib (v4.70)
    - mysql-connector-java-8.0.30.jar (for MySQL)
    B4X:
    - MiniORMUtils.b4xlib (v3.30)
Option 2:
  1. Download and put Pakai Server (5.00).b4xtemplate to B4J Additional Libraries folder.
  2. Use LibDownloader to download the additional b4xlibs after you have created a new project.
  3. If you want to use MySQL database, you also need the mysql connector library.
Create a Project
  1. Start B4J IDE
  2. Select New from File menu and click on Pakai Server (5.xx)
  3. Confirm the Project Folder
  4. Enter the Project Name as you desired then click OK button.
  5. A project is created and ready to run under the default settings.
Running the Project
  1. Click Compile & Run (F5) from the Project menu or click the play button on the toolbar.
  2. When the project has finished to compile, hover you mouse pointer to the AppStart sub.
  3. Click on the highlighted link to open the app on your web browser.
  4. The index page will be loaded.
    It shows a web application with CRUD functionality to:
    - add a new product (Create),
    - search for a product (Read),
    - edit an existing product (Update) and
    - delete a product (Delete).
  5. The API endpoints are generated based on RESTful API principal.
  6. To see the list of APIs, click the API link with a gear icon on top navigation bar.
  7. The API documentation or help page displays the endpoints for GET, POST, PUT and DELETE represented in different colours.
  8. You can click on any item to expand the section.
Performing Tests

GET
  1. Click on the first endpoint name [GET] Read all Categories.
  2. Click on the green Submit button and wait for the response.
  3. The response should return a JSON response with Code 200.
POST
  1. To test a POST endpoint, click the third item which labeled [POST] Add new Category.
  2. Edit the content inside the Body text area
  3. Click on the purple Submit button and wait for the response.
  4. The response should return a JSON response with Code 201.
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #2: Server Configuration

The server configuration is handled by EndsMeet library.

Option 1: Using Config File (Recommended)
  1. By default, app.UseConfigFile is set to True in Main module.
  2. When the project is compile for the first time, a config.ini file is created inside the Objects folder.
  3. You can open the file using any text editor and update the settings.
  4. The project will load the settings based on the values set in the config.ini file.
  5. Note that any settings set in config.ini file will override the settings set programmatically.
  6. Line begins with # is disabled.
  7. Example the following setting will not be applied (default value will be applied):
    B4X:
    #API_VERSIONING=False
  8. The project need to be recompiled after changes are made during development.
  9. During production, the app need to be exited and rerun to load the new settings.
Available Configurations
  • HOME_TITLE
    Set the title of the app
  • APP_TITLE
    Set the title for the browser tab
  • APP_TRADEMARK
    Set the name beside the logo on navigation bar
  • APP_COPYRIGHT
    Set the copyright text at the footer
  • ROOT_URL (default: http://127.0.0.1)
    Set the server URL.
    You can set a domain name in production.
  • ROOT_PATH (default: <empty>)
    You can be set to other name e.g /web
  • API_NAME (default: api)
    Better leave it as default.
    If you changed it, you need to use app.api.Name in the code.
    You also need to edit html templates and JavaScript files.
  • API_VERSIONING (default: False)
    If set to True, you need to handle the uri elements in Api handlers.
  • API_VERBOSE_MODE (default: False)
    Set the API response in verbose format
  • API_ORDERED_KEYS (default: False)
    Set whether the generated API response keys follow specified order
  • PORT (default: 8080)
    Set the server port
    Make sure the port number is not used by another service or blocked by the firewall.
  • SSL_PORT (default: 0)
    Set port if using SSL protocol
    It is recommended to use SSL protocol in production.
    If SSLPort number is set to 0, SSL is disabled.
    You can set the value to non-zero to enable it e.g 443
  • SSL_KEYSTORE_DIR
    Set directory where the SSL located
  • SSL_KEYSTORE_FILE
    Set the keystore file name
  • SSL_KEYSTORE_PASSWORD
    Set the keystore password
  • SMTP_SERVER
    Set the smtp server
  • SMTP_USERNAME
    Set the smtp username
  • SMTP_PASSWORD
    Set the smtp password
  • SMTP_PORT
    Set the smtp port
  • SMTP_USESSL
    Set to use SSL for smtp
  • HTML_BODY
    Set whether to use HTML for the email content
  • ADMIN_EMAIL
    Set the admin email for notification
  • DbType
    Set the type of database
  • DbFile
    Set the database file name (SQLite)
  • DbDir
    Set the directory of database (SQLite)
  • DbName
    Set the name of database (MySQL)
  • DbHost
    Set the server name or IP of database (MySQL)
  • DbPort (default: 3306)
    Set the server port of database (MySQL)
  • DriverClass
    Set the driver class of database (MySQL)
  • JdbcUrl
    Set the jdbc url of database (MySQL)
  • User
    Set the user name of database (MySQL)
  • Password
    Set the user password of database (MySQL)
  • MaxPoolSize
    Set the server maximum pool size (MySQL)
SSL configuration
  1. If SSL port is 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.
Database configuration
  1. Default DbType is set to SQLite.
  2. You can change the DbFile as you like e.g app.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:/app/db or C:\\app\\db
  5. If you want to use MySQL as backend database, enable or uncomment the following settings:
    - DbName
    - DbHost
    - DbPort
    - DriverClass
    - JdbcUrl
    - User
    - Password
    - MaxPoolSize
Option 2: Set Configuration Programmatically
  1. If app.UseConfigFile is set to False, config file is not used.
  2. To override the settings, you need to specify each of them programmatically.
  3. Any changes to the settings need to recompile the project or jar.
The following settings are available in EndsMeet class that can be overridden:
ApiSettings (api)
- Name
- Versioning
- PayloadType
- ContentType
- EnableHelp
- VerboseMode
- OrderedKeys
SslSettings (ssl)
- Enabled
- Port
- KeystoreDir
- KeystoreFile
- KeystorePassword
CorsSettings (cors)
- Enabled
- Path
- Settings
EmailSettings (email)
- SmtpUserName
- SmtpPassword
- SmtpServer
- SmtpUseSsl
- SmtpPort
StaticFilesSettings (staticfiles)
- Folder
- Browsable

Example:
B4X:
app.api.VerboseMode = True
app.api.OrderedKeys = True
app.api.ContentType = WebApiUtils.CONTENT_TYPE_XML
app.ssl.Port = 443
app.ssl.KeystoreFile = "keystore.jks"

Note:
Make sure to assign the values before calling app.Start
If you set app.UseConfigFile = True, setting the value programmatically will not override it. Except the setting is commented in config file.
Not all settings can be set in config.ini
Some settings still need to be set programatically.

I will add more tutorials explaining how to use OrderedKeys and XML support when I am free in the future.
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #3: Routing

EndsMeet has 4 http methods available:
  • Get
  • Post
  • Put
  • Delete
  1. Each route needs to match the path correctly.
  2. We can use MethodAvailable2 sub to check the client app is making a valid http call allowed or set in the Main module.
    B4X:
    app.Get("/categories", "CategoriesWebHandler")
    app.Get("/api/categories", "CategoriesApiHandler")
    app.Get("/api/categories/*", "CategoriesApiHandler")
    app.Post("/api/categories", "CategoriesApiHandler")
    app.Put("/api/categories/*", "CategoriesApiHandler")
    app.Delete("/api/categories/*", "CategoriesApiHandler")
  3. From the example above, "/api/categories/*" endpoint is allowed for Put.
    PUT "/api/categories/3" is allowed
    PUT "/api/categories" is not allowed
  4. If MethodAvailable2 returns False, we can return error message by calling ReturnMethodNotAllow sub.
    B4X:
    If ElementMatch("id") Then
        If Main.app.MethodAvailable2(Method, "/api/categories/*", Me) Then
            Select Method
                Case "GET"
                    GetCategoryById(ElementId)
                    Return
                Case "PUT"
                    UpdateCategoryById(ElementId)
                    Return
                Case "DELETE"
                    DeleteCategoryById(ElementId)
                    Return
            End Select
        End If
        ReturnMethodNotAllow
        Return
    End If
Conventions use for Server Handler
  1. When working with Pakai framework, the following naming convention are recommended 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/XML
    • Web Handler - to read the Request from the URI without the /api path and output the Response as HTML
  2. Example:
    • CategoriesApiHandler
    • CategoriesWebHandler
  3. As you can guess, CategoriesApiHandler is use for taking care of the API endpoints while CategoriesWebHandler is use to display the web page.
  4. IndexWebHandler is use to display the index page when a user browse to the root path.
  5. The index page calls the API endpoints from ProductsApiHandler and FindApiHandler.
  6. HelpHandler is use to display the API documentation page. It will be use to call any API endpoint that you have created.
  7. Each Web handler is linked to its respective JavaScript file to make AJAX calls and process the returned JSON Response from an Api handler.
Adding Server Handler
  1. There are 2 ways to add a Server Handler.
  2. We can click on the menu Project, Add New Module, Class Module,
  3. A better way is to right-click on the Handlers group in Modules tab and select Server Handler.
    In this way, later we don't need to drag the class into the group.
  4. Enter the name of the handler and click OK. It is recommended to use name associated with the model/route.
    e.g /api/users -> UsersApiHandler
  5. An empty class with a Handle sub is generated.
    B4X:
    'Handler class
    Sub Class_Globals
    
    End Sub
    
    Public Sub Initialize
    
    End Sub
    
    Sub Handle(req As ServletRequest, resp As ServletResponse)
    
    End Sub
  6. Remember to add the new route in Main module before calling app.Start.
  7. Example:
    B4X:
    app.Post("/api/users", "UsersApiHandler")
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #4: Connecting to Database

By default, Pakai uses MiniORMUtils library to interact with the database.
You can also use SQL library if you don't want to use this library.

InitDatabase
  1. Make sure you have set the correct ConnectionInfo.
  2. If you want to switch from SQLite to MySQL, select MySQL from the Build Configurations dropdown list.
  3. If the configuration does not match, it will show an error message and the application will be terminated immediately.
CreateDatabase
  1. This sub sets up the database by creating tables and inserting some dummy data.
  2. You can modify the database schema or add other columns to the tables.
 
Last edited:

aeric

Expert
Licensed User
Longtime User
Part #5: Using Code Snippets
  1. We can use Code Snippets included in WebApiUtils to help us to generate some boilerplate code in Api Handler.
  2. Let's delete all the code but left the Class_Globals sub.
    Note: We can also use a Standard class.
  3. Put your cursor inside Class_Globals sub, now start typing "globals".
    Select the "Api Class Globals" Code Snippet using the Up/Down key and press Enter.
  4. The result is the following:
    B4X:
    Sub Class_Globals
            Private Request As ServletRequest
            Private Response As ServletResponse
            Private HRM As HttpResponseMessage
            Private DB As MiniORM
            Private Method As String
            Private Elements() As String
            Private ElementId As Int
    End Sub
  5. The variable names are quite self explanatory. We will be using HttpResponseMessage from WebApiUtils and MiniORM class.
  6. Put the cursor after the Class_Globals sub and start typing "handler".
    Use the Up/Down key to select "Api Handler" code snippet then press Enter.
  7. The default code is added. You will notice there are some texts are highlighted.
  8. Replace "EndPoints" with "Users" for plural word and "EndPoint" with "User" for singular word.
  9. Press Tab key to switch to next occurrences if they exist.
    Here, we also need to change the "TableName" to the name of your users table.
  10. When the cursor returned to the first highlighted text, we can press Enter to accept the changes.
  11. Now the handler is ready. You can make further customization to this handler.
  12. Take note that we still need to create the users table and add the handler to the server.
    Main:
    app.Get("/api/users", "UsersApiHandler")
    app.Get("/api/users/*", "UsersApiHandler")
    app.Post("/api/users", "UsersApiHandler")
    app.Put("/api/users/*", "UsersApiHandler")
  13. To add the endpoints to API documentation, add the handler to Initialize sub in HelpHandler.
    HelpHandler:
    Public Sub Initialize
        AllMethods.Initialize
        AllGroups.Initialize
        Handlers.Initialize
        Handlers.Add("CategoriesApiHandler")
        Handlers.Add("ProductsApiHandler")
        Handlers.Add("FindApiHandler")
        Handlers.Add("UsersApiHandler")
    End Sub
  14. You can use BuildMethods sub to build the endpoint section.
 
Last edited:
Top