diff --git a/404.html b/404.html index da6ff81..544946b 100644 --- a/404.html +++ b/404.html @@ -17,7 +17,7 @@
- + \ No newline at end of file diff --git a/assets/banner-cards/flash-advanced-handler-default-implementations.png b/assets/banner-cards/flash-advanced-handler-default-implementations.png index f8c2a64..37bcb1c 100644 Binary files a/assets/banner-cards/flash-advanced-handler-default-implementations.png and b/assets/banner-cards/flash-advanced-handler-default-implementations.png differ diff --git a/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.js b/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.js new file mode 100644 index 0000000..8cad2eb --- /dev/null +++ b/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.js @@ -0,0 +1,29 @@ +import{_ as a,c as e,a0 as i,o as t}from"./chunks/framework.p2VkXzrt.js";const n="/assets/flash-fullstack.D96XNhET.png",u=JSON.parse('{"title":"🌐 Fullstack Development","description":"","frontmatter":{"banner_title":"Flash - Fullstack Development","banner_description":"Build fullstack apps with Flash, frontend and backend in one jar.","head":[["meta",{"name":"twitter:image","content":"/assets/banner-cards/flash-advanced-fullstack-development.png"}],["meta",{"name":"twitter:image:src","content":"https://docs.pixel-services.com/assets/banner-cards/flash-advanced-fullstack-development.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:height","content":"1280"}],["meta",{"name":"twitter:image:width","content":"669"}],["meta",{"name":"twitter:description","content":""}]]},"headers":[],"relativePath":"flash/advanced/fullstack-development.md","filePath":"flash/advanced/fullstack-development.md"}'),l={name:"flash/advanced/fullstack-development.md"};function o(r,s,p,h,d,c){return t(),e("div",null,s[0]||(s[0]=[i('

🌐 Fullstack Development ​

Fullstack development involves building both the front-end (user interface) and back-end (server logic, database) of a web application. A fullstack developer is responsible for the entire application, ensuring a smooth connection between the two layers.

Popular fullstack frameworks include:

⚑ Fullstack Development with Flash ​

Developing and packaging a fullstack application can be complex, but Flash simplifies the process with built-in tools and quality-of-life features. With Flash, you can:

Flash Fullstack Development

πŸš€ Serving Frontend with Flash ​

Flash’s dynamic file server enables seamless fullstack development by allowing you to serve frontend assets alongside backend logic. This is made possible by the RESOURCESTREAM source type, which serves files from the JAR’s resources folder.

βœ… Deployment Workflow ​

The recommended workflow for packaging a fullstack Flash application:

  1. Compile the frontend application (React, Vue, Angular, etc.).
  2. Place the compiled files inside the resources folder.
  3. Build the JAR file with both frontend and backend code.
  4. Deploy the JAR, serving both frontend and backend seamlessly.

This approach works for any frontend framework that compiles to static files, such as:

❔ Setting up a Fullstack Flash Application ​

To get started with fullstack development using Flash, you will first need to choose a frontend framework and set up the build process to compile the frontend assets. This guide will cover only some of the most popular javascript frontend build tools, but the process is similar for others.

πŸ› οΈ Setting up the Frontend Build Process ​

WARNING

When building a frontend application with a javascript framework that will be served on a subpath (e.g., /app), you need to specify the homepage in the package.json file. This ensures that the frontend assets are correctly loaded from the subpath. Using a subpath and forgetting to set the homepage will result in broken asset links and a potentially non-functional frontend.

json
{
+    "homepage": "/your-subpath"
+}

πŸ›œ Serve the Frontend with Flash ​

Once you have compiled the frontend assets and placed them in the resources/frontend folder, you can serve them using Flash's dynamic file server. This server will serve the frontend assets from the JAR's resources folder.

INFO

NOTE: The following example is assuming you plan to serve the frontend from the root path (/). If you plan to serve the frontend from a subpath (e.g., /app), you will need to adjust the endpoint path accordingly by adding a trailing /*.

java
public class Example {
+    public static void main(String[] args) {
+        FlashServer server = new FlashServer(8080);
+
+        server.serveDynamic("/*", new DynamicFileServerConfiguration(
+            true,
+            "frontend", // points to the resources/frontend folder
+            "index.html",
+            SourceType.RESOURCESTREAM
+        ));
+        
+        server.start();
+    }
+}

πŸš€ Package and Deploy your app! ​

With the frontend and backend code in place, you can now build the JAR file and deploy it to your server. The JAR file will contain both the frontend and backend code, making it easy to deploy and run your fullstack application.

All you've left to do is run the jarfile on any machine that has Java installed, and your fullstack application will be up and running!

`,27)]))}const g=a(l,[["render",o]]);export{u as __pageData,g as default}; diff --git a/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.lean.js b/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.lean.js new file mode 100644 index 0000000..8cad2eb --- /dev/null +++ b/assets/flash_advanced_fullstack-development.md.DFJ2Nfm_.lean.js @@ -0,0 +1,29 @@ +import{_ as a,c as e,a0 as i,o as t}from"./chunks/framework.p2VkXzrt.js";const n="/assets/flash-fullstack.D96XNhET.png",u=JSON.parse('{"title":"🌐 Fullstack Development","description":"","frontmatter":{"banner_title":"Flash - Fullstack Development","banner_description":"Build fullstack apps with Flash, frontend and backend in one jar.","head":[["meta",{"name":"twitter:image","content":"/assets/banner-cards/flash-advanced-fullstack-development.png"}],["meta",{"name":"twitter:image:src","content":"https://docs.pixel-services.com/assets/banner-cards/flash-advanced-fullstack-development.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:height","content":"1280"}],["meta",{"name":"twitter:image:width","content":"669"}],["meta",{"name":"twitter:description","content":""}]]},"headers":[],"relativePath":"flash/advanced/fullstack-development.md","filePath":"flash/advanced/fullstack-development.md"}'),l={name:"flash/advanced/fullstack-development.md"};function o(r,s,p,h,d,c){return t(),e("div",null,s[0]||(s[0]=[i('

🌐 Fullstack Development ​

Fullstack development involves building both the front-end (user interface) and back-end (server logic, database) of a web application. A fullstack developer is responsible for the entire application, ensuring a smooth connection between the two layers.

Popular fullstack frameworks include:

⚑ Fullstack Development with Flash ​

Developing and packaging a fullstack application can be complex, but Flash simplifies the process with built-in tools and quality-of-life features. With Flash, you can:

Flash Fullstack Development

πŸš€ Serving Frontend with Flash ​

Flash’s dynamic file server enables seamless fullstack development by allowing you to serve frontend assets alongside backend logic. This is made possible by the RESOURCESTREAM source type, which serves files from the JAR’s resources folder.

βœ… Deployment Workflow ​

The recommended workflow for packaging a fullstack Flash application:

  1. Compile the frontend application (React, Vue, Angular, etc.).
  2. Place the compiled files inside the resources folder.
  3. Build the JAR file with both frontend and backend code.
  4. Deploy the JAR, serving both frontend and backend seamlessly.

This approach works for any frontend framework that compiles to static files, such as:

❔ Setting up a Fullstack Flash Application ​

To get started with fullstack development using Flash, you will first need to choose a frontend framework and set up the build process to compile the frontend assets. This guide will cover only some of the most popular javascript frontend build tools, but the process is similar for others.

πŸ› οΈ Setting up the Frontend Build Process ​

WARNING

When building a frontend application with a javascript framework that will be served on a subpath (e.g., /app), you need to specify the homepage in the package.json file. This ensures that the frontend assets are correctly loaded from the subpath. Using a subpath and forgetting to set the homepage will result in broken asset links and a potentially non-functional frontend.

json
{
+    "homepage": "/your-subpath"
+}

πŸ›œ Serve the Frontend with Flash ​

Once you have compiled the frontend assets and placed them in the resources/frontend folder, you can serve them using Flash's dynamic file server. This server will serve the frontend assets from the JAR's resources folder.

INFO

NOTE: The following example is assuming you plan to serve the frontend from the root path (/). If you plan to serve the frontend from a subpath (e.g., /app), you will need to adjust the endpoint path accordingly by adding a trailing /*.

java
public class Example {
+    public static void main(String[] args) {
+        FlashServer server = new FlashServer(8080);
+
+        server.serveDynamic("/*", new DynamicFileServerConfiguration(
+            true,
+            "frontend", // points to the resources/frontend folder
+            "index.html",
+            SourceType.RESOURCESTREAM
+        ));
+        
+        server.start();
+    }
+}

πŸš€ Package and Deploy your app! ​

With the frontend and backend code in place, you can now build the JAR file and deploy it to your server. The JAR file will contain both the frontend and backend code, making it easy to deploy and run your fullstack application.

All you've left to do is run the jarfile on any machine that has Java installed, and your fullstack application will be up and running!

`,27)]))}const g=a(l,[["render",o]]);export{u as __pageData,g as default}; diff --git a/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.js b/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.js new file mode 100644 index 0000000..dbb9453 --- /dev/null +++ b/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.js @@ -0,0 +1,117 @@ +import{_ as i,c as a,a0 as n,o as t}from"./chunks/framework.p2VkXzrt.js";const e="/assets/hdichain.FX-X2Mhu.png",o=JSON.parse('{"title":"⚑ Handler Default Implementations (HDI)","description":"","frontmatter":{"banner_title":"Flash - Handler Default Implementations","banner_description":"Leverage HDIs for cleaner and more maintainable route logic.","head":[["meta",{"name":"twitter:image","content":"/assets/banner-cards/flash-advanced-handler-default-implementations.png"}],["meta",{"name":"twitter:image:src","content":"https://docs.pixel-services.com/assets/banner-cards/flash-advanced-handler-default-implementations.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:height","content":"1280"}],["meta",{"name":"twitter:image:width","content":"669"}],["meta",{"name":"twitter:description","content":""}]]},"headers":[],"relativePath":"flash/advanced/handler-default-implementations.md","filePath":"flash/advanced/handler-default-implementations.md"}'),h={name:"flash/advanced/handler-default-implementations.md"};function l(p,s,k,r,d,E){return t(),a("div",null,s[0]||(s[0]=[n(`

⚑ Handler Default Implementations (HDI) ​

Handler Default Implementations (HDIs) provide an elegant way to standardize common behaviors across multiple request handlers. By defining base handlers that extend RequestHandler (or chaining multiple base handlers together), you can modularize logic for common tasks like authentication, user data retrieval, and rate limiting.

HDIs are designed using the Chain of Responsibility pattern, making it easy to handle requests with layered logic.

πŸ”— How It Works ​

Instead of repeating the same logic in each handler, create abstract handler classes that define common functionality. Your handler implementations then extend these base classes, inheriting the shared behavior while implementing the request-specific logic.

Semantics of an HDI ​

Creating an HDI is simple, but it's useful to follow some guidelines for clarity and maintainability:

  1. Base HDI Class: ​

  2. Handler Implementation: ​

πŸ›  Example: API Key Authentication ​

Now let's go over a simple example to demonstrate how HDIs work. Imagine you need to authenticate API requests by checking an API key. You can create an abstract APIKeyProtectedHandler that extends RequestHandler and handles the API key authentication:

java
public abstract class APIKeyProtectedHandler extends RequestHandler {
+    protected String apiKey;
+
+    public APIKeyProtectedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    public Object handle() {
+        apiKey = req.header("X-API-Key");
+
+        if (apiKey == null || !isValidApiKey(apiKey)) {
+            res.status(403);
+            res.type("application/json");
+            return "{\\"error\\":\\"Invalid API Key\\"}";
+        }
+
+        return handleAuthorized();
+    }
+
+    protected abstract Object handleAuthorized();
+
+    private boolean isValidApiKey(String key) {
+        // Implement key validation logic, e.g., checking against a database
+        return true;
+    }
+}

Now, your API handler implementation only need to extend APIKeyProtectedHandler, ensuring every request has a valid API key before executing its logic:

java
@RouteInfo(method = HttpMethod.GET, path = "/data")
+public class GetDataHandler extends APIKeyProtectedHandler {
+    public GetDataHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleAuthorized() {
+        res.type("application/json");
+        return "{\\"data\\":\\"Your API response here\\"}";
+    }
+}

πŸ—οΈ Chaining HDIs for Modular Logic ​

HDI Chain

HDIs can be chained together to create multiple layers of logic. For example, if you need to authenticate a user and fetch their data from a database, you can create two HDIs:

java
public abstract class ProtectedHandler extends RequestHandler {
+    protected String authToken;
+
+    public ProtectedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    public Object handle() {
+        authToken = req.header("Authorization");
+        if (authToken == null || !isValidToken(authToken)) {
+            res.status(401);
+            res.type("application/json");
+            return "{\\"error\\":\\"Unauthorized\\"}";
+        }
+        return handleAuthenticated();
+    }
+
+    protected abstract Object handleAuthenticated();
+}
java
public abstract class AuthenticatedHandler extends ProtectedHandler {
+    protected User user;
+    private String authToken; // inherited from ProtectedHandler
+
+    public AuthenticatedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleAuthenticated() {
+        user = getUserFromDatabase(authToken);
+        if (user == null) {
+            res.status(403);
+            res.type("application/json");
+            return "{\\"error\\":\\"User not found\\"}";
+        }
+        return handleWithUser();
+    }
+
+    protected abstract Object handleWithUser();
+}
java
@RouteInfo(endpoint = "/profile", method = HttpMethod.GET)
+public class UserProfileHandler extends AuthenticatedHandler {
+    public UserProfileHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleWithUser() {
+        res.type("application/json");
+        return "{\\"username\\":\\"" + user.getUsername() + "\\"}";
+    }
+}
`,22)]))}const y=i(h,[["render",l]]);export{o as __pageData,y as default}; diff --git a/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.lean.js b/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.lean.js new file mode 100644 index 0000000..dbb9453 --- /dev/null +++ b/assets/flash_advanced_handler-default-implementations.md.Bai_t_s4.lean.js @@ -0,0 +1,117 @@ +import{_ as i,c as a,a0 as n,o as t}from"./chunks/framework.p2VkXzrt.js";const e="/assets/hdichain.FX-X2Mhu.png",o=JSON.parse('{"title":"⚑ Handler Default Implementations (HDI)","description":"","frontmatter":{"banner_title":"Flash - Handler Default Implementations","banner_description":"Leverage HDIs for cleaner and more maintainable route logic.","head":[["meta",{"name":"twitter:image","content":"/assets/banner-cards/flash-advanced-handler-default-implementations.png"}],["meta",{"name":"twitter:image:src","content":"https://docs.pixel-services.com/assets/banner-cards/flash-advanced-handler-default-implementations.png"}],["meta",{"name":"twitter:card","content":"summary_large_image"}],["meta",{"name":"twitter:image:height","content":"1280"}],["meta",{"name":"twitter:image:width","content":"669"}],["meta",{"name":"twitter:description","content":""}]]},"headers":[],"relativePath":"flash/advanced/handler-default-implementations.md","filePath":"flash/advanced/handler-default-implementations.md"}'),h={name:"flash/advanced/handler-default-implementations.md"};function l(p,s,k,r,d,E){return t(),a("div",null,s[0]||(s[0]=[n(`

⚑ Handler Default Implementations (HDI) ​

Handler Default Implementations (HDIs) provide an elegant way to standardize common behaviors across multiple request handlers. By defining base handlers that extend RequestHandler (or chaining multiple base handlers together), you can modularize logic for common tasks like authentication, user data retrieval, and rate limiting.

HDIs are designed using the Chain of Responsibility pattern, making it easy to handle requests with layered logic.

πŸ”— How It Works ​

Instead of repeating the same logic in each handler, create abstract handler classes that define common functionality. Your handler implementations then extend these base classes, inheriting the shared behavior while implementing the request-specific logic.

Semantics of an HDI ​

Creating an HDI is simple, but it's useful to follow some guidelines for clarity and maintainability:

  1. Base HDI Class: ​

  2. Handler Implementation: ​

πŸ›  Example: API Key Authentication ​

Now let's go over a simple example to demonstrate how HDIs work. Imagine you need to authenticate API requests by checking an API key. You can create an abstract APIKeyProtectedHandler that extends RequestHandler and handles the API key authentication:

java
public abstract class APIKeyProtectedHandler extends RequestHandler {
+    protected String apiKey;
+
+    public APIKeyProtectedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    public Object handle() {
+        apiKey = req.header("X-API-Key");
+
+        if (apiKey == null || !isValidApiKey(apiKey)) {
+            res.status(403);
+            res.type("application/json");
+            return "{\\"error\\":\\"Invalid API Key\\"}";
+        }
+
+        return handleAuthorized();
+    }
+
+    protected abstract Object handleAuthorized();
+
+    private boolean isValidApiKey(String key) {
+        // Implement key validation logic, e.g., checking against a database
+        return true;
+    }
+}

Now, your API handler implementation only need to extend APIKeyProtectedHandler, ensuring every request has a valid API key before executing its logic:

java
@RouteInfo(method = HttpMethod.GET, path = "/data")
+public class GetDataHandler extends APIKeyProtectedHandler {
+    public GetDataHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleAuthorized() {
+        res.type("application/json");
+        return "{\\"data\\":\\"Your API response here\\"}";
+    }
+}

πŸ—οΈ Chaining HDIs for Modular Logic ​

HDI Chain

HDIs can be chained together to create multiple layers of logic. For example, if you need to authenticate a user and fetch their data from a database, you can create two HDIs:

java
public abstract class ProtectedHandler extends RequestHandler {
+    protected String authToken;
+
+    public ProtectedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    public Object handle() {
+        authToken = req.header("Authorization");
+        if (authToken == null || !isValidToken(authToken)) {
+            res.status(401);
+            res.type("application/json");
+            return "{\\"error\\":\\"Unauthorized\\"}";
+        }
+        return handleAuthenticated();
+    }
+
+    protected abstract Object handleAuthenticated();
+}
java
public abstract class AuthenticatedHandler extends ProtectedHandler {
+    protected User user;
+    private String authToken; // inherited from ProtectedHandler
+
+    public AuthenticatedHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleAuthenticated() {
+        user = getUserFromDatabase(authToken);
+        if (user == null) {
+            res.status(403);
+            res.type("application/json");
+            return "{\\"error\\":\\"User not found\\"}";
+        }
+        return handleWithUser();
+    }
+
+    protected abstract Object handleWithUser();
+}
java
@RouteInfo(endpoint = "/profile", method = HttpMethod.GET)
+public class UserProfileHandler extends AuthenticatedHandler {
+    public UserProfileHandler(Request req, Response res) {
+        super(req, res);
+    }
+
+    @Override
+    protected Object handleWithUser() {
+        res.type("application/json");
+        return "{\\"username\\":\\"" + user.getUsername() + "\\"}";
+    }
+}
`,22)]))}const y=i(h,[["render",l]]);export{o as __pageData,y as default}; diff --git a/assets/hdichain.FX-X2Mhu.png b/assets/hdichain.FX-X2Mhu.png new file mode 100644 index 0000000..6645258 Binary files /dev/null and b/assets/hdichain.FX-X2Mhu.png differ diff --git a/flash/advanced/fullstack-development.html b/flash/advanced/fullstack-development.html index 97b7f7d..fa6def8 100644 --- a/flash/advanced/fullstack-development.html +++ b/flash/advanced/fullstack-development.html @@ -3,7 +3,7 @@ - 🌐 Fullstack Development with Flash | Pixel Services Docs + 🌐 Fullstack Development | Pixel Services Docs @@ -13,7 +13,7 @@ - + @@ -25,8 +25,8 @@ -
Skip to content

🌐 Fullstack Development with Flash ​

Fullstack development involves building both the front-end (user interface) and back-end (server logic, database) of a web application. A fullstack developer is responsible for the entire application, ensuring a smooth connection between the two layers.

Popular fullstack frameworks include:

⚑ Fullstack Development with Flash ​

Developing and packaging a fullstack application can be complex, but Flash simplifies the process with built-in tools and quality-of-life features. With Flash, you can:

  • Serve both frontend and backend from a single application.
  • Bundle everything into a single JAR file for easy deployment.
  • Leverage HDIs for clean, modular and maintainable route logic.

Flash Fullstack Development

πŸš€ Serving Frontend with Flash ​

Flash’s dynamic file server enables seamless fullstack development by allowing you to serve frontend assets alongside backend logic. This is made possible by the RESOURCESTREAM source type, which serves files from the JAR’s resources folder.

βœ… Deployment Workflow ​

The recommended workflow for packaging a fullstack Flash application:

  1. Compile the frontend application (React, Vue, Angular, etc.).
  2. Place the compiled files inside the resources folder.
  3. Build the JAR file with both frontend and backend code.
  4. Deploy the JAR, serving both frontend and backend seamlessly.

This approach works for any frontend framework that compiles to static files, such as:

  • React (npm run build)
  • Vue.js (npm run build)
  • Angular (ng build --prod)

❔ Setting up a Fullstack Flash Application ​

To get started with fullstack development using Flash, you will first need to choose a frontend framework and set up the build process to compile the frontend assets. This guide will cover only some of the most popular javascript frontend build tools, but the process is similar for others.

πŸ› οΈ Setting up the Frontend Build Process ​

WARNING

When building a frontend application with a javascript framework that will be served from a subdirectory (e.g., /app), you need to specify the homepage in the package.json file. This ensures that the frontend assets are correctly loaded from the subdirectory. Using a subdirectory and forgetting to set the homepage will result in broken asset links and a potentially non-functional frontend.

json
{
-    "homepage": "/your-subdirectory"
+    
Skip to content

🌐 Fullstack Development ​

Fullstack development involves building both the front-end (user interface) and back-end (server logic, database) of a web application. A fullstack developer is responsible for the entire application, ensuring a smooth connection between the two layers.

Popular fullstack frameworks include:

⚑ Fullstack Development with Flash ​

Developing and packaging a fullstack application can be complex, but Flash simplifies the process with built-in tools and quality-of-life features. With Flash, you can:

  • Serve both frontend and backend from a single application.
  • Bundle everything into a single JAR file for easy deployment.
  • Leverage HDI's for clean, modular and maintainable route logic.

Flash Fullstack Development

πŸš€ Serving Frontend with Flash ​

Flash’s dynamic file server enables seamless fullstack development by allowing you to serve frontend assets alongside backend logic. This is made possible by the RESOURCESTREAM source type, which serves files from the JAR’s resources folder.

βœ… Deployment Workflow ​

The recommended workflow for packaging a fullstack Flash application:

  1. Compile the frontend application (React, Vue, Angular, etc.).
  2. Place the compiled files inside the resources folder.
  3. Build the JAR file with both frontend and backend code.
  4. Deploy the JAR, serving both frontend and backend seamlessly.

This approach works for any frontend framework that compiles to static files, such as:

  • React (npm run build)
  • Vue.js (npm run build)
  • Angular (ng build --prod)

❔ Setting up a Fullstack Flash Application ​

To get started with fullstack development using Flash, you will first need to choose a frontend framework and set up the build process to compile the frontend assets. This guide will cover only some of the most popular javascript frontend build tools, but the process is similar for others.

πŸ› οΈ Setting up the Frontend Build Process ​

WARNING

When building a frontend application with a javascript framework that will be served on a subpath (e.g., /app), you need to specify the homepage in the package.json file. This ensures that the frontend assets are correctly loaded from the subpath. Using a subpath and forgetting to set the homepage will result in broken asset links and a potentially non-functional frontend.

json
{
+    "homepage": "/your-subpath"
 }
  • Vite :

    Click to expand
    1. Install Vite on your project if it's not already installed or scaffold a new Vite project (follow the official guide).
    2. Edit the vite.config.js or vite.config.ts build section to output the compiled files to the resources/frontend folder of your Flash project (see example below).
    typescript
        // ...
         import path from 'path'
         export default defineConfig({
    @@ -40,7 +40,7 @@
         "scripts": {
             "build": "parcel build src/index.html --out-dir ../path/to/your/src/main/resources/frontend"
         }
    -}
  • The output of your Parcel build will be placed in the resources/frontend folder of your Flash project, ready to be packaged into the JAR file.

πŸ›œ Serve the Frontend with Flash ​

Once you have compiled the frontend assets and placed them in the resources/frontend folder, you can serve them using Flash's dynamic file server. This server will serve the frontend assets from the JAR's resources folder.

INFO

NOTE: The following example is assuming you plan to serve the frontend from the root path (/). If you plan to serve the frontend from a subdirectory (e.g., /app), you will need to adjust the endpoint path accordingly by adding a trailing /*.

java
public class Example {
+}
  • The output of your Parcel build will be placed in the resources/frontend folder of your Flash project, ready to be packaged into the JAR file.
  • πŸ›œ Serve the Frontend with Flash ​

    Once you have compiled the frontend assets and placed them in the resources/frontend folder, you can serve them using Flash's dynamic file server. This server will serve the frontend assets from the JAR's resources folder.

    INFO

    NOTE: The following example is assuming you plan to serve the frontend from the root path (/). If you plan to serve the frontend from a subpath (e.g., /app), you will need to adjust the endpoint path accordingly by adding a trailing /*.

    java
    public class Example {
         public static void main(String[] args) {
             FlashServer server = new FlashServer(8080);
     
    @@ -54,7 +54,7 @@
             server.start();
         }
     }

    πŸš€ Package and Deploy your app! ​

    With the frontend and backend code in place, you can now build the JAR file and deploy it to your server. The JAR file will contain both the frontend and backend code, making it easy to deploy and run your fullstack application.

    All you've left to do is run the jarfile on any machine that has Java installed, and your fullstack application will be up and running!

    - + \ No newline at end of file diff --git a/flash/advanced/handler-default-implementations.html b/flash/advanced/handler-default-implementations.html index da4ab90..61a2ab4 100644 --- a/flash/advanced/handler-default-implementations.html +++ b/flash/advanced/handler-default-implementations.html @@ -13,7 +13,7 @@ - + @@ -25,7 +25,36 @@ -
    Skip to content

    ⚑ Handler Default Implementations (HDI) ​

    HDI's provide an elegant and reliable way to standardize common behaviors across multiple request handlers. By defining base handlers that extend RequestHandler (or even chaining multiple base handlers), you can modularize your logic for aspects like authentication, user data retrieval, and rate limiting.

    πŸ”— How It Works ​

    Instead of implementing repeated logic in every handler, you create abstract handler classes that encapsulate common functionality. Your actual route handlers then extend these base classes, inheriting their behavior while focusing purely on request-specific logic.

    πŸ›  Example: API Key Authentication ​

    Imagine you want to protect API endpoints with an authentication key by checking it against a database. You can create an abstract APIKeyProtectedHandler that extends RequestHandler and implements the authentication logic:

    java
    public abstract class APIKeyProtectedHandler extends RequestHandler {
    +    
    Skip to content

    ⚑ Handler Default Implementations (HDI) ​

    Handler Default Implementations (HDIs) provide an elegant way to standardize common behaviors across multiple request handlers. By defining base handlers that extend RequestHandler (or chaining multiple base handlers together), you can modularize logic for common tasks like authentication, user data retrieval, and rate limiting.

    HDIs are designed using the Chain of Responsibility pattern, making it easy to handle requests with layered logic.

    πŸ”— How It Works ​

    Instead of repeating the same logic in each handler, create abstract handler classes that define common functionality. Your handler implementations then extend these base classes, inheriting the shared behavior while implementing the request-specific logic.

    Semantics of an HDI ​

    Creating an HDI is simple, but it's useful to follow some guidelines for clarity and maintainability:

    1. Base HDI Class: ​

      • Extends: The base HDI class should extend RequestHandler.
      • Constructor: The constructor must call the super constructor with Request and Response objects.
      • Override: Override the handle method to include common behavior. The handle method should return the response to the client and should call the Abstract Handler Method, which is implemented by the handler or next HDI in the chain.
        java
        @Override
        +public Object handle() {
        +    // Common logic here, then call the abstract method
        +    return handleCustom();
        +}
      • Abstract Handler Method: Define an abstract method that must be implemented by the handler to provide custom logic. It should look like this:
        java
        protected abstract Object handleCustom();
      • Protected Fields: If needed, declare protected fields in the base class to pass data between handlers in the chain.

        INFO

        Protected fields are accessible to the handler implementation inside the Abstract Handler Method. Example HDI :

        java
        public abstract class MyHDI extends RequestHandler {
        +    protected String data; 
        +    public BaseHandler(Request req, Response res) {
        +        super(req, res);
        +    }
        +    @Override
        +    public Object handle() {
        +        data = "Some data"; // Set the data
        +        return handleCustom();
        +    }
        +    protected abstract Object handleCustom();
        +}

        Example Handler Implementation :

        java
        public class MyHandler extends MyHDI {
        +    public MyHandler(Request req, Response res) {
        +        super(req, res);
        +    }
        +    @Override
        +    protected Object handleCustom() {
        +        // The data is accessible here
        +        System.out.println(data);
        +        return "Response";
        +    }
        +}
    2. Handler Implementation: ​

      • Extends: The handler should extend the HDI class (or be the final handler in the chain).
      • Constructor: The constructor should call the super constructor with Request and Response objects.
      • Implement: Implement the Abstract Handler Method from the HDI.
      • Response Logic: The response logic should be in the abstract method, and its return value is sent to the client.
        java
        @Override
        +protected Object handleCustom() {
        +      // Custom logic here
        +      return "Response";
        +}
      • Protected Fields: The handler implementation can access data from the HDI using the protected fields, inside the Abstract Handler Method.

    πŸ›  Example: API Key Authentication ​

    Now let's go over a simple example to demonstrate how HDIs work. Imagine you need to authenticate API requests by checking an API key. You can create an abstract APIKeyProtectedHandler that extends RequestHandler and handles the API key authentication:

    java
    public abstract class APIKeyProtectedHandler extends RequestHandler {
         protected String apiKey;
     
         public APIKeyProtectedHandler(Request req, Response res) {
    @@ -45,15 +74,13 @@
             return handleAuthorized();
         }
     
    -    // Implement this method in your actual handlers
         protected abstract Object handleAuthorized();
     
         private boolean isValidApiKey(String key) {
             // Implement key validation logic, e.g., checking against a database
    -        // ...
             return true;
         }
    -}

    Now, your actual API handlers only need to extend APIKeyProtectedHandler, ensuring every request has a valid API key before executing its logic:

    java
    @RouteInfo(method = HttpMethod.GET, path = "/data")
    +}

    Now, your API handler implementation only need to extend APIKeyProtectedHandler, ensuring every request has a valid API key before executing its logic:

    java
    @RouteInfo(method = HttpMethod.GET, path = "/data")
     public class GetDataHandler extends APIKeyProtectedHandler {
         public GetDataHandler(Request req, Response res) {
             super(req, res);
    @@ -64,7 +91,7 @@
             res.type("application/json");
             return "{\"data\":\"Your API response here\"}";
         }
    -}

    πŸ—οΈ Chaining HDIs for Modular Logic ​

    HDIs can be chained together to compose multiple layers of behavior. For example, imagine you want to authenticate users with a token and fetch their data from a database. You can create two abstract handlers that extend one another:

    • ProtectedHandler ensures authentication.
    java
    public abstract class ProtectedHandler extends RequestHandler {
    +}

    πŸ—οΈ Chaining HDIs for Modular Logic ​

    HDI Chain

    HDIs can be chained together to create multiple layers of logic. For example, if you need to authenticate a user and fetch their data from a database, you can create two HDIs:

    • ProtectedHandler ensures authentication.
    java
    public abstract class ProtectedHandler extends RequestHandler {
         protected String authToken;
     
         public ProtectedHandler(Request req, Response res) {
    @@ -103,11 +130,8 @@
         }
     
         protected abstract Object handleWithUser();
    -}
    • Your actual implementation handler UserProfileHandler extends AuthenticatedHandler and implements handleWithUser to ensure the user is authenticated and their profile data has been fetched before proceeding.
    java
    @RouteInfo(endpoint = "/profile", method = HttpMethod.GET)
    +}
    • Your handler implementation UserProfileHandler extends AuthenticatedHandler and implements handleWithUser to ensure the user is authenticated and their profile data has been fetched before proceeding.
    java
    @RouteInfo(endpoint = "/profile", method = HttpMethod.GET)
     public class UserProfileHandler extends AuthenticatedHandler {
    -    // inherited from AuthenticatedHandler
    -    private String username = user.getUsername();
    -    
         public UserProfileHandler(Request req, Response res) {
             super(req, res);
         }
    @@ -115,10 +139,10 @@
         @Override
         protected Object handleWithUser() {
             res.type("application/json");
    -        return "{\"username\":\"" + username + "\"}";
    +        return "{\"username\":\"" + user.getUsername() + "\"}";
         }
     }
    - + \ No newline at end of file diff --git a/flash/core-concepts/handlers.html b/flash/core-concepts/handlers.html index 87eb123..27f2494 100644 --- a/flash/core-concepts/handlers.html +++ b/flash/core-concepts/handlers.html @@ -41,7 +41,7 @@ server.get("/hello", (req, res) -> { return "Hello, World!"; });

    Both RequestHandler and SimpleHandler can specify the router behavior by the naming convention of the endpoint used to register the handler.

    • Literal Routing: /hello
      Will match exactly /hello

    • Parametrized Routing: /hello/:name
      Will match /hello/John, /hello/Alice, etc.

    • Dynamic Routing: /hello/*
      Will match /hello/../..

    - + \ No newline at end of file diff --git a/flash/core-concepts/request-handler.html b/flash/core-concepts/request-handler.html index 8fa8559..32a934c 100644 --- a/flash/core-concepts/request-handler.html +++ b/flash/core-concepts/request-handler.html @@ -37,7 +37,7 @@ return response; } }

    WARNING

    Any logic that needs to be executed before the request handler is registered must be done within the constructor.

    Request Handler methods ​

    The RequestHandler class provides several methods that can be used to interact with the request and response objects easily and safely. Following are listed the methods available in the RequestHandler class, with a brief description of their purpose:

    MethodParamsDescription
    getRequestBody()noneReturns a JSONObject representation of the request body.
    getSpecification()noneReturns an instance of HandlerSpecification containing all sorts of information about the handler.
    expectedRequestParameter()String name, descriptionReturns an instance of ExpectedRequestParameter for the specified parameter name.
    expectedBodyField()String name, descriptionReturns an instance of ExpectedBodyField for the specified field name.
    expectedBodyFile()String name, descriptionReturns an instance of ExpectedBodyFile for the specified file name.

    (More on the ExpectedRequestParameter, ExpectedBodyField, and ExpectedBodyFile classes in the next section).

    - + \ No newline at end of file diff --git a/flash/core-concepts/request-response.html b/flash/core-concepts/request-response.html index a739f47..6fb6bd9 100644 --- a/flash/core-concepts/request-response.html +++ b/flash/core-concepts/request-response.html @@ -92,7 +92,7 @@ return "File saved at: " + myFile.getAbsolutePath(); } }

    This time, you will need to use a tool like Postman to send a POST request to /helloFile with a multipart form data body containing a file named myFile. You should receive a response like File saved at: <path> where <path> is the location where the server saved the file.

    - + \ No newline at end of file diff --git a/flash/core-concepts/server-router.html b/flash/core-concepts/server-router.html index 5f8f991..999ee7a 100644 --- a/flash/core-concepts/server-router.html +++ b/flash/core-concepts/server-router.html @@ -49,7 +49,7 @@ return response; } }

    In the example above, we create an /api router and register the MyHandler class to handle requests on the /api/hello endpoint.

    This is because the path property of the RouteInfo annotation is relative to the base path of the router, which in this case is /api.

    Visiting /api/hello from your browser will result in the response Hello, world!.

    - + \ No newline at end of file diff --git a/flash/core-concepts/websockets.html b/flash/core-concepts/websockets.html index 880d505..65d83c1 100644 --- a/flash/core-concepts/websockets.html +++ b/flash/core-concepts/websockets.html @@ -58,7 +58,7 @@ server.start(); } }

    Interacting with Websockets sessions ​

    The WebSocketSession object provides methods to interact with the Websocket session, such as sending messages, closing the connection, and getting the remote address and session ID.

    MethodParamsDescription
    getChannel()noneReturns an instance of AsynchronousSocketChannel useful for retrieving info about the client .
    getRequestInfo()noneReturns an instance of RequestInfo containing all sorts of information about the request (headers, method, path etc.) .
    getPath()noneReturns the path to the websocket endpoint as a String.
    getId()noneReturns the id of the websocket session as a String, useful if you want to keep track of the connected clients in a custom manager.
    getBuffer()noneReturns the ByteBuffer for that session.
    sendMessage()String messageSends the message to the client as a String. it's up to the developer to stringify and de-stringify any data you want to send back and forth
    close()noneCloses the websocket session.

    NOTE

    WebsocketHandler includes a setId(String id) method for overriding the default session ID. Unless you have a specific reason to change it, it's best to leave it as is.

    Similarly, the setBuffer(ByteBuffer buffer) method allows you to override the default buffer. If you're unsure about this, it's recommended to keep the default setting.

    - + \ No newline at end of file diff --git a/flash/file-serving/dynamic-file-server.html b/flash/file-serving/dynamic-file-server.html index d46b462..5fb7aab 100644 --- a/flash/file-serving/dynamic-file-server.html +++ b/flash/file-serving/dynamic-file-server.html @@ -53,7 +53,7 @@ )); } } - + \ No newline at end of file diff --git a/flash/file-serving/static-file-server.html b/flash/file-serving/static-file-server.html index 92f0e92..b5a145b 100644 --- a/flash/file-serving/static-file-server.html +++ b/flash/file-serving/static-file-server.html @@ -53,7 +53,7 @@ )); } } - + \ No newline at end of file diff --git a/flash/index.html b/flash/index.html index 85e2b76..65571a9 100644 --- a/flash/index.html +++ b/flash/index.html @@ -26,7 +26,7 @@
    Skip to content

    ⚑ Flash ​

    Flash is a simple, modern and fast expressive web framework written in Java. The project is maintained by Pixel Services and the open-source community.

    Our Team ​

    Say hello to the Pixel Services team !

    Relism

    Relism

    Developer

    Sieadev

    Sieadev

    Developer

    - + \ No newline at end of file diff --git a/flash/introduction/installation.html b/flash/introduction/installation.html index bb8fee0..e7aa12c 100644 --- a/flash/introduction/installation.html +++ b/flash/introduction/installation.html @@ -44,7 +44,7 @@ }
  • And the dependency :

    groovy
    dependencies {
         implementation 'com.pixelservices:flash:{{ latestVersion }}'
     }
  • ⚑ Latest version:
    - + \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index 73ed51d..13bb0ae 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"flash_advanced_fullstack-development.md":"B124NtWL","flash_advanced_handler-default-implementations.md":"BSoFk9xD","flash_core-concepts_handlers.md":"B1156l1I","flash_core-concepts_request-handler.md":"fjZWLpOw","flash_core-concepts_request-response.md":"3C-3EYgj","flash_core-concepts_server-router.md":"BtmNSZRo","flash_core-concepts_websockets.md":"ByGVX96c","flash_file-serving_dynamic-file-server.md":"DY_r4ecH","flash_file-serving_static-file-server.md":"BvN0FZB2","flash_index.md":"E5zPbZtg","flash_introduction_installation.md":"BEOKwAAp","index.md":"CgmTRI0Q","mobot_index.md":"Be0Zoetq","serverlibraries_index.md":"CeIqSPIs"} +{"flash_advanced_fullstack-development.md":"DFJ2Nfm_","flash_advanced_handler-default-implementations.md":"Bai_t_s4","flash_core-concepts_handlers.md":"B1156l1I","flash_core-concepts_request-handler.md":"fjZWLpOw","flash_core-concepts_request-response.md":"3C-3EYgj","flash_core-concepts_server-router.md":"BtmNSZRo","flash_core-concepts_websockets.md":"ByGVX96c","flash_file-serving_dynamic-file-server.md":"DY_r4ecH","flash_file-serving_static-file-server.md":"BvN0FZB2","flash_index.md":"E5zPbZtg","flash_introduction_installation.md":"BEOKwAAp","index.md":"CgmTRI0Q","mobot_index.md":"Be0Zoetq","serverlibraries_index.md":"CeIqSPIs"} diff --git a/index.html b/index.html index 2e90c3b..4684307 100644 --- a/index.html +++ b/index.html @@ -26,7 +26,7 @@
    Skip to content
    - + \ No newline at end of file diff --git a/mobot/index.html b/mobot/index.html index 9378216..4a287cb 100644 --- a/mobot/index.html +++ b/mobot/index.html @@ -26,7 +26,7 @@
    Skip to content
    - + \ No newline at end of file diff --git a/serverlibraries/index.html b/serverlibraries/index.html index a471d2a..5dd19e8 100644 --- a/serverlibraries/index.html +++ b/serverlibraries/index.html @@ -26,7 +26,7 @@
    Skip to content
    - + \ No newline at end of file