olliNiinivaara / GuildenStern

Modular multithreading HTTP/1.1 + WebSocket server framework
MIT License
80 stars 7 forks source link

Exception Handling issues #15

Closed ITwrx closed 10 months ago

ITwrx commented 10 months ago

Hi, I think my type mismatch problem in #14 was actually due to exception handling and not necessarily gcsafe (yet?). The GuildenStern httpserver request callback specifies {.raises: [].}, but the GuildenStern README example does not. I guess I can use proc handleGet() = only if there are no possible exceptions in any procs that are called during that request handling? I haven't had to deal with these exception pragma notations before with any other server/framework, so i've been trying to brush up on it, but i'm not having much luck getting it to compile. The compiler keeps complaining about different procs and their possible exceptions. Below is an example of my testing code with current exception appeasement attempt. :) I'm just trying to perform one sql statement with sqliteral and output in a nim SCF template to see how it's all supposed to work together.

main_gs.nim

import cgi, strtabs, guildenstern/[dispatcher, httpserver]
import "gs_test.nimf"

proc handleGet() {.gcsafe, raises: [].} =
  let html = bkTestTemplate()
  reply(html)  

let getserver = newHttpServer(handleGet)
getserver.start(5050)
joinThread(getserver.thread)

gs_test.nimf

CatachableError below was just a catchall attempt to try to get it to compile. It was complaining about SQLError:ObjectType, but i wasn't sure how to specify that.

#? stdtmpl(subsChar = '$', metaChar = '#')
#import "sql_ss_model"
#proc bkTestTemplate*(): string {.raises: CatchableError.} =
#let siteSections = getAllSiteSections()
# result = ""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Just Testing</title>
</head>
<body>
<h1>Just testing!</h1>
#for siteSection in siteSections:
<h2>Title: ${siteSection.title}</h2>
#end for
</body>
</html>
#end proc

sql_ss_model.nim

from db_connector/sqlite3 import column_type, SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB
import sqliteral

type
  SiteSection* = object
    title*, linkTitle*, navMenuInclusion*, landingType*, status*: string
    id*, parentId*: int

proc toTuple*[T: tuple](prepared: PStmt, _: typedesc[T]): T =
  var col = 0.int32
  for value in fields(result):
    let datatype = column_type(prepared, col)
    case datatype
      of SQLITE_INTEGER: value = toDb(getInt(prepared, col))
      of SQLITE_FLOAT: value = toDb(getFloat(prepared, col))
      of SQLITE_TEXT: value = toDb(getCString(prepared, col))
      of SQLITE_BLOB: value = toDb(getSeq(prepared, col))
      else: discard
    col += 1

proc getAllSiteSections*(): seq[SiteSection] {.raises: [SQLError, Exception].} =
  const Schema = "CREATE TABLE IF NOT EXISTS SiteSections(id INTEGER PRIMARY KEY, title TEXT NOT NULL, link_title TEXT, nav_menu_inclusion TEXT, landing_type TEXT, parent_id INTEGER, status TEXT)"
  var db: SQLiteral
  db.openDatabase("BetterWeb.db", Schema)
  let statement = "SELECT * FROM SiteSections"
  type
    RowTuple = tuple[id: DbValue, title: DbValue, linkTitle: DbValue, navMenuInclusion: DbValue, landingType: DbValue, parentId: DbValue, status: DbValue]
  let prepared = db.prepareSql(statement)
  db.exec(prepared)
  for row in db.rows(prepared): 
    echo row.toTuple(RowTuple)
  db.close()

i'm not sure about the last few lines of sql_ss_model.nim. All the sqliteral examples use prepareStatements() instead of prepareSql(), and i haven't got to test it yet due to the exceptions issues.

Thanks! I'm hoping if i can get my little test working i won't have to bother you so much. :)

olliNiinivaara commented 10 months ago

handleGet() can call procs that may raise exceptions, but you need to handle them with the try statement. Basically like this:

proc handleGet() {.gcsafe, raises: [].} =
  try:
    let html = bkTestTemplate()
    reply(html)
  except: reply(Http500)
ITwrx commented 10 months ago

Wow, i can't believe i never thought to try that, although i think the nim docs could be more explicit that the try is mandatory for compilation in this situation. I guess i thought you only needed try when you wanted to catch and handle specific exceptions. It compiles without any {.raises.} pragmas now. Thanks for the help!