Skip to content

Commit

Permalink
add route decorators #176
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethosa committed Nov 14, 2023
1 parent c61cbb7 commit 6388a63
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 10 deletions.
2 changes: 1 addition & 1 deletion happyx.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

description = "Macro-oriented asynchronous web-framework written with ♥"
author = "HapticX"
version = "3.2.1"
version = "3.3.0"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
Expand Down
3 changes: 2 additions & 1 deletion src/happyx.nim
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ import
happyx/sugar/[use, sgr, js, style],
happyx/spa/[renderer, state, components, translatable, tag],
happyx/tmpl_engine/[engine],
happyx/routing/[mounting, routing],
happyx/routing/[mounting, routing, decorators],
happyx/ssr/utils


Expand All @@ -336,6 +336,7 @@ export
queries,
renderer,
state,
decorators,
components,
translatable,
style,
Expand Down
4 changes: 2 additions & 2 deletions src/happyx/core/constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ const
nim_2_0_0* = (NimMajor, NimMinor, NimPatch) >= (2, 0, 0)
# Framework version
HpxMajor* = 3
HpxMinor* = 2
HpxPatch* = 2
HpxMinor* = 3
HpxPatch* = 0
HpxVersion* = $HpxMajor & "." & $HpxMinor & "." & $HpxPatch


Expand Down
48 changes: 48 additions & 0 deletions src/happyx/routing/decorators.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## # Decorators 🔌
##
## Provides convenient wrapper to create route decorators
##
import
macros,
tables,
base64


export base64


type
decoratorImpl* = proc(httpMethods: seq[string], routePath: string, statementList: NimNode)


var decorators* {.compileTime.} = newTable[string, decoratorImpl]()


proc regDecorator*(decoratorName: string, decorator: decoratorImpl) {.compileTime.} =
decorators[decoratorName] = decorator


proc authBasicDecoratorImpl(httpMethods: seq[string], routePath: string, statementList: NimNode) =
statementList.insert(0, parseStmt"""
var (username, password) = ("", "")
if not headers.hasKey("Authorization"):
var statusCode = 401
return {"response": "failure", "reason": "You should to use Basic authorization!"}
else:
(username, password) = block:
let code = headers["Authorization"].split(" ")[1]
let decoded = base64.decode(code).split(":", 1)
(decoded[0], decoded[1])"""
)


proc getUserAgentDecoratorImpl(httpMethods: seq[string], routePath: string, statementList: NimNode) =
statementList.insert(0, parseStmt"""
var userAgent = navigator.userAgent
"""
)


static:
regDecorator("AuthBasic", authBasicDecoratorImpl)
regDecorator("GetUserAgent", getUserAgentDecoratorImpl)
12 changes: 9 additions & 3 deletions src/happyx/spa/renderer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import
./translatable,
../core/[exceptions, constants],
../private/[macro_utils],
../routing/[routing, mounting],
../routing/[routing, mounting, decorators],
../sugar/[sgr, js]


Expand Down Expand Up @@ -532,15 +532,21 @@ macro routes*(app: App, body: untyped): untyped =

var
cookiesInVar = newDotExpr(ident"document", ident"cookie")
nextRouteDecorators: seq[string] = @[]

for statement in body:
if statement.kind in [nnkCommand, nnkCall]:
if statement.kind in [nnkCommand, nnkCall, nnkPrefix]:
if statement[^1].kind == nnkStmtList:
# Check variable usage
if statement[^1].isIdentUsed(ident"cookies"):
statement[^1].insert(0, newVarStmt(ident"cookies", cookiesInVar))
# @DecoratorName
if statement.kind == nnkPrefix and $statement[0] == "@" and statement[1].kind == nnkIdent:
nextRouteDecorators.add($statement[1])

if statement.len == 2 and statement[0].kind == nnkStrLit:
elif statement.len == 2 and statement[0].kind == nnkStrLit:
for route in nextRouteDecorators:
decorators[route](@[], $statement[0], statement[1])
let exported = exportRouteArgs(
iPath,
statement[0],
Expand Down
26 changes: 23 additions & 3 deletions src/happyx/ssr/server.nim
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ import
../spa/[tag, renderer, translatable],
../core/[exceptions, constants, queries],
../private/[macro_utils],
../routing/[routing, mounting],
../routing/[routing, mounting, decorators],
../sugar/sgr

export
Expand Down Expand Up @@ -850,10 +850,13 @@ socketToSsr.onmessage=function(m){
val[1]
))

var
nextRouteDecorators: seq[string] = @[]

for statement in body:
if statement.kind == nnkDiscardStmt:
continue
if statement.kind in [nnkCall, nnkCommand]:
if statement.kind in [nnkCall, nnkCommand, nnkPrefix]:
if statement[^1].kind == nnkStmtList:
# Check variable usage
if statement[^1].isIdentUsed(ident"statusCode"):
Expand All @@ -862,19 +865,30 @@ socketToSsr.onmessage=function(m){
statement[^1].insert(0, newVarStmt(ident"outHeaders", newCall("newCustomHeaders")))
if statement[^1].isIdentUsed(ident"outCookies") or statement[^1].isIdentUsed(ident"startSession"):
statement[^1].insert(0, newVarStmt(ident"outCookies", cookiesOutVar))
# @DecoratorName
if statement.kind == nnkPrefix and $statement[0] == "@" and statement[1].kind == nnkIdent:
nextRouteDecorators.add($statement[1])
# "/...": statement list
if statement[1].kind == nnkStmtList and statement[0].kind == nnkStrLit:
elif statement[1].kind == nnkStmtList and statement[0].kind == nnkStrLit:
detectReturnStmt(statement[1])
for route in nextRouteDecorators:
decorators[route](@["GET"], $statement[0], statement[1])
let exported = exportRouteArgs(pathIdent, statement[0], statement[1])
if exported.len > 0: # /my/path/with{custom:int}/{param:path}
ifStmt.add(exported)
else: # /just-my-path
ifStmt.add(newNimNode(nnkElifBranch).add(
newCall("==", pathIdent, statement[0]), statement[1]
))
nextRouteDecorators = @[]
# [get, post, ...] "/...": statement list
elif statement.len == 3 and statement[2].kind == nnkStmtList and statement[0].kind == nnkBracket and statement[1].kind == nnkStrLit and statement[0].len > 0:
detectReturnStmt(statement[2])
var httpMethods: seq[string] = @[]
for i in statement[0]:
httpMethods.add($i)
for route in nextRouteDecorators:
decorators[route](httpMethods, $statement[1], statement[2])
let exported = exportRouteArgs(pathIdent, statement[1], statement[2])
var methods = newNimNode(nnkBracket)
for i in statement[0]:
Expand All @@ -894,10 +908,13 @@ socketToSsr.onmessage=function(m){
newCall("==", pathIdent, statement[1])
), statement[2]
))
nextRouteDecorators = @[]
# reqMethod "/...":
# ...
elif statement[0].kind == nnkIdent and statement[0] != ident"mount" and statement[1].kind in {nnkStrLit, nnkTripleStrLit, nnkInfix}:
let name = ($statement[0]).toUpper()
for route in nextRouteDecorators:
decorators[route](@[$statement[0]], $statement[1], statement[2])
if name == "STATICDIR":
if statement[1].kind in [nnkStrLit, nnkTripleStrLit]:
ifStmt.insert(
Expand Down Expand Up @@ -1122,6 +1139,7 @@ socketToSsr.onmessage=function(m){
newCall("==", pathIdent, statement[1]),
statement[2]
))
nextRouteDecorators = @[]
# notfound: statement list
elif statement[1].kind == nnkStmtList and statement[0].kind == nnkIdent:
case ($statement[0]).toLower()
Expand Down Expand Up @@ -1257,6 +1275,8 @@ socketToSsr.onmessage=function(m){
immutableVars.add(newIdentDefs(ident"inCookies", newEmptyNode(), cookiesInVar))
if stmtList.isIdentUsed(ident"reqMethod"):
immutableVars.add(newIdentDefs(ident"reqMethod", newEmptyNode(), reqMethod))
if stmtList.isIdentUsed(ident"headers"):
immutableVars.add(newIdentDefs(ident"headers", newEmptyNode(), headers))
immutableVars.add(newIdentDefs(ident"hostname", newEmptyNode(), hostname))
when enableDebugSsrMacro:
echo result.toStrLit
Expand Down
9 changes: 9 additions & 0 deletions tests/testc6.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@ serve("127.0.0.1", 5000):
"/":
return "Hello, world!"

@AuthBasic # username and password will in your code.
get "/user{id}":
echo username
echo password
return {"response": {
"id": id,
"username": username,
"password": password
}}
4 changes: 4 additions & 0 deletions tests/testjs14.nim
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ appRoutes("app"):
CTest(id = 0):
"hello"

@GetUserAgent
"/issue154":
tDiv:
"Your user agent is"
{userAgent}
tDiv: {catStatus}
var
dogStatus = "superposition"
Expand Down

0 comments on commit 6388a63

Please sign in to comment.