Repository: HapticX/happyx (language: python)

Issue:
Swagger/OpenAPI: Same routes with different http methods are not generated 🐛
**Describe the bug** 🐛
Automatic API/Doc generation omits identical routes with different http methods.

**To Reproduce** 👨‍🔬
Steps to reproduce the behavior:
1. Define two routes inside the serve block: get "/myRoute" and post "/myRoute"
2. Compile and run: nim c -r ./myHappyxServer.nim
3. Open swagger api generation in web browser: http://[my_ip]:[my_port]/docs/swagger

**Expected behavior** 🤔
There should be an entry for the get route as well as for the post route

**Actual behavior**
Only the post route is shown, apparently the last defined route "wins"

**Minimal Code Example**

```
import happyx

serve "0.0.0.0", 8041:
  get "/myRoute":
    statusCode = 200
    return 0
  post "/myRoute":
    statusCode = 200
    return 0

```

**Screenshots** 🖼
![happyxswagger](https://github.com/HapticX/happyx/assets/46842029/23585bbc-b2e6-4b05-92c9-60778ce79992)

 - OS: FreeBSD 13.1
 - head
 -  ssr
 - Nim
 - 2.0
 - HTTP Server Default

Swagger/OpenAPI: Same routes with different http methods are not generated 🐛
**Describe the bug** 🐛
Automatic API/Doc generation omits identical routes with different http methods.

**To Reproduce** 👨‍🔬
Steps to reproduce the behavior:
1. Define two routes inside the serve block: get "/myRoute" and post "/myRoute"
2. Compile and run: nim c -r ./myHappyxServer.nim
3. Open swagger api generation in web browser: http://[my_ip]:[my_port]/docs/swagger

**Expected behavior** 🤔
There should be an entry for the get route as well as for the post route

**Actual behavior**
Only the post route is shown, apparently the last defined route "wins"

**Minimal Code Example**

```
import happyx

serve "0.0.0.0", 8041:
  get "/myRoute":
    statusCode = 200
    return 0
  post "/myRoute":
    statusCode = 200
    return 0

```

**Screenshots** 🖼
![happyxswagger](https://github.com/HapticX/happyx/assets/46842029/23585bbc-b2e6-4b05-92c9-60778ce79992)

 - OS: FreeBSD 13.1
 - head
 -  ssr
 - Nim
 - 2.0
 - HTTP Server Default



Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index d4a64071..d17b04cc 100755
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
 
 [![VS Code Plugin](https://img.shields.io/badge/Plugin-1b1e2b?style=for-the-badge&logo=visualstudiocode&logoColor=f1fa8c&label=VS%20Code&labelColor=2b2e3b)](https://github.com/HapticX/hpx-vs-code)
 
-[![Python Bindings](https://img.shields.io/badge/Bindings-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)](https://pypi.org/project/happyx/)
+[![Python Bindings](https://img.shields.io/badge/Bindings-1b1e2b?style=for-the-badge&logo=python&logoColor=f1fa8c&label=Python&labelColor=2b2e3b)](https://pypi.org/project/happyxpy/)
 [![NodeJS Bindings](https://img.shields.io/badge/Bindings-1b1e2b?style=for-the-badge&logo=npm&logoColor=f1fa8c&label=NodeJS&labelColor=2b2e3b)](https://www.npmjs.com/package/happyx)
 
 </div>
diff --git a/bindings/python/happyxpy/happyx.pyd b/bindings/python/happyxpy/happyx.pyd
index 316b404f..2a778ff5 100644
Binary files a/bindings/python/happyxpy/happyx.pyd and b/bindings/python/happyxpy/happyx.pyd differ
diff --git a/examples/website/src/docs/introduction.nim b/examples/website/src/docs/introduction.nim
index 1a108890..8364be34 100644
--- a/examples/website/src/docs/introduction.nim
+++ b/examples/website/src/docs/introduction.nim
@@ -82,8 +82,8 @@ component Introduction:
           tTr:
             tTd: "PyPI"
             tTd:
-              tA(href = "https://pypi.org/project/happyx/"):
-                tImg(class = "h-12 lg:h-10 xl:h-8", alt = "PyPI Downloads", src = "https://img.shields.io/pypi/dm/happyx?style=for-the-badge")
+              tA(href = "https://pypi.org/project/happyxpy/"):
+                tImg(class = "h-12 lg:h-10 xl:h-8", alt = "PyPI Downloads", src = "https://img.shields.io/pypi/dm/happyxpy?style=for-the-badge")
           tTr:
             tTd: "npm"
             tTd:
diff --git a/examples/website/src/pages/roadmap.nim b/examples/website/src/pages/roadmap.nim
index 509d5095..7a7fedfc 100644
--- a/examples/website/src/pages/roadmap.nim
+++ b/examples/website/src/pages/roadmap.nim
@@ -123,7 +123,14 @@ mount RoadMap:
                   tLi: {translate"New rendering system 🧪"}
                   tLi: {translate"Functional components ✨"}
                   tLi: {translate"Generics for request models 🔥"}
-                
+          # v4.0.0
+          Card:
+            tDiv(class = "w-full flex flex-col items-center gap-2 p-4 lg:p-2 xl:p-0"):
+              tP(class = "text-4xl lg:text-2xl xl:text-lg font-semibold"):
+                "v4.0.0"
+              tP(class = "w-full text-2xl lg:text-lg xl:text-base"):
+                # TODO: translation
+                {translate"Remove regex from routing 🔌"}
           # Future
           Card:
             tDiv(class = "w-full flex flex-col items-center gap-2 p-4 lg:p-2 xl:p-0"):
diff --git a/happyx.nimble b/happyx.nimble
index ce008cfd..554ac013 100755
--- a/happyx.nimble
+++ b/happyx.nimble
@@ -2,7 +2,7 @@
 
 description = "Macro-oriented asynchronous web-framework written with ♥"
 author = "HapticX"
-version = "4.0.0"
+version = "4.0.1"
 license = "MIT"
 srcDir = "src"
 installExt = @["nim"]
diff --git a/src/happyx/core/constants.nim b/src/happyx/core/constants.nim
index d6618704..65b0dbf6 100755
--- a/src/happyx/core/constants.nim
+++ b/src/happyx/core/constants.nim
@@ -99,7 +99,7 @@ const
   # Framework version
   HpxMajor* = 4
   HpxMinor* = 0
-  HpxPatch* = 0
+  HpxPatch* = 1
   HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch
 
 
diff --git a/src/happyx/spa/renderer.nim b/src/happyx/spa/renderer.nim
index 6c21d140..31c80c4c 100644
--- a/src/happyx/spa/renderer.nim
+++ b/src/happyx/spa/renderer.nim
@@ -137,8 +137,8 @@ when enableDefaultComponents:
 
 when defined(js):
   const uniqueMacroIndex = CacheCounter"uniqueMacroIndex"
-macro elem*(name: untyped): untyped =
-  ## `elem` macro is just shortcut for
+macro rf*(name: untyped): untyped =
+  ## `rf` macro is just shortcut for
   ## 
   ## .. code-block::nim
   ##    block:
@@ -153,7 +153,7 @@ macro elem*(name: untyped): untyped =
     let
       nameStr = $name
       uniqName = fmt"_res{uniqueMacroIndex.value}"
-    newStmtList(
+    result = newStmtList(
       newNimNode(nnkVarSection).add(newIdentDefs(
         ident(uniqName), ident"Element"
       )),
@@ -266,8 +266,12 @@ when defined(js):
     for key, val in vdomAttrs.pairs:
       if not domAttrs.hasKey(key):
         dom.setAttribute(key, val)
+        if dom.nodeName == "INPUT" and key == "value":
+          dom.InputElement.value = val
       elif domAttrs[key] != val:
         dom.setAttribute(key, val)
+        if dom.nodeName == "INPUT" and key == "value":
+          dom.InputElement.value = val
     for key, val in domAttrs.pairs:
       if not vdomAttrs.hasKey(key):
         dom.removeAttribute(key)
diff --git a/src/happyx/spa/state.nim b/src/happyx/spa/state.nim
index e909c8cb..3d0781ce 100644
--- a/src/happyx/spa/state.nim
+++ b/src/happyx/spa/state.nim
@@ -221,12 +221,22 @@ proc set*[T](self: State[T], value: T) =
     application.router()
 
 
-func `[]`*[T](self: State[openarray[T]], idx: int): T =
+func `[]`*[T, U](self: State[array[T, U]], idx: int): T =
   ## Returns State's item at `idx` index.
   self.val[idx]
 
 
-func `[]`*[T](self: State[openarray[T]], idx: State[int]): T =
+func `[]`*[T](self: State[seq[T]], idx: int): T =
+  ## Returns State's item at `idx` index.
+  self.val[idx]
+
+
+func `[]`*[T, U](self: State[array[T, U]], idx: State[int]): T =
+  ## Returns State's item at `idx` index.
+  self.val[idx.val]
+
+
+func `[]`*[T](self: State[seq[T]], idx: State[int]): T =
   ## Returns State's item at `idx` index.
   self.val[idx.val]
 
diff --git a/src/happyx/ssr/docs/autodocs.nim b/src/happyx/ssr/docs/autodocs.nim
index ef2a0d96..4038a7e8 100644
--- a/src/happyx/ssr/docs/autodocs.nim
+++ b/src/happyx/ssr/docs/autodocs.nim
@@ -322,8 +322,9 @@ proc openApiDocs*(docsData: NimNode): NimNode =
           # Skip useless routes
           if route.httpMethod[0] in ["MIDDLEWARE", "STATICFILE", "STATIC", "NOTFOUND"]:
             continue
-          result["paths"][route.path] = %*{}
-          result["components"][route.path] = %*{}
+          if not result["paths"].hasKey(route.path):
+            result["paths"][route.path] = %*{}
+            result["components"][route.path] = %*{}
           let decscription = route.description.replace(
             re2"@openapi\s*\{(\s*\w+\s*[^\n]+|\s*@(params|responses)\s*\{[^\}]+?}\s*)+\s*\}", ""
           )
diff --git a/src/happyx/ssr/server.nim b/src/happyx/ssr/server.nim
index af1e9862..f5e92b9c 100755
--- a/src/happyx/ssr/server.nim
+++ b/src/happyx/ssr/server.nim
@@ -1543,6 +1543,14 @@ socketToSsr.onmessage=function(m){
     stmtList.add(newCall(
       "handleJvmRequest", ident"self", ident"req", ident"urlPath"
     ))
+
+  when not (exportPython or exportJvm or defined(napibuild)):
+    var returnStmt = newStmtList(newNimNode(nnkReturnStmt).add(newLit""))
+    detectReturnStmt(returnStmt)
+    methodTable.mgetOrPut(
+      "OPTIONS", newNimNode(nnkIfStmt)
+    ).add(exportRouteArgs(pathIdent, newLit"/{p:path}", returnStmt))
+
   for key in methodTable.keys():
     caseRequestMethodsStmt.add(newNimNode(nnkOfBranch).add(
       newLit(parseEnum[HttpMethod](key)),


Test patch:
diff --git a/tests/testc20.nim b/tests/testc20.nim
index 7b0e2a0d..25d8d795 100644
--- a/tests/testc20.nim
+++ b/tests/testc20.nim
@@ -14,6 +14,13 @@ serve("127.0.0.1", 5000):
     echo data
     return ""
 
+  get "/issue287":
+    statusCode = 200
+    return 0
+  post "/issue287":
+    statusCode = 200
+    return 0
+
   onException:
     echo "Exception"
     echo e.name