SSPkrolik / nimongo

Pure Nim lang MongoDB driver
http://sspkrolik.github.io/nimongo
MIT License
101 stars 20 forks source link

Question - not bug #85

Open UNIcodeX opened 4 years ago

UNIcodeX commented 4 years ago

Describe the bug A clear and concise description of what the bug is. What am I doing wrong??

import nimongo/bson
import nimongo/mongo

const
  database     = "test"

var
  sm: Mongo = newMongo(host="192.168.0.127")           ## Mongo synchronous client
  # am: AsyncMongo = newAsyncMongo() ## Mongo asynchronous client

let
  sdb: Database[Mongo] = sm[database]
  # adb: Database[AsyncMongo] = am[database]
  colTest: Collection[Mongo] = sdb["test"]
  # aAds: Collection[AsyncMongo] = adb["ads"]

discard sm.connect()
if not sdb.authenticate(username="user", password="pass"):
  let err = getCurrentException()
  raise
else:
  echo "authenticated!"

echo colTest.find(%*{"active": true}).all()

gives error:

Hint:  [Link]
Hint: 91777 LOC; 9.636 sec; 110.582MiB peakmem; Debug build; proj: C:\Users\jaredfields\Desktop\code\sandbox\tmp.nim; out: C:\Users\jaredfields\Desktop\code\sandbox\tmp.exe [SuccessX]
Hint: C:\Users\jaredfields\Desktop\code\sandbox\tmp.exe  [Exec]
C:\Users\jaredfields\Desktop\code\sandbox\tmp.nim(27) tmp
C:\Users\jaredfields\.choosenim\toolchains\nim-1.2.0\lib\system\fatal.nim(49) sysFatal
Error: unhandled exception: no exception to reraise [ReraiseError]
Error: execution of an external program failed: 'C:\Users\jaredfields\Desktop\code\sandbox\tmp.exe '

To Reproduce Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior A clear and concise description of what you expected to happen.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

JohnAD commented 4 years ago

Are you trying to choose the database to authenticate the connection against instead of the default admin database?

It is my understanding that the authentication occurs during connect(). You might try passing this information by using the URI in newMongoWithURI rather than newMongo.

Per the spec, you can choose both the database and auth-database like this:

mongodb://user:pass@192.168.0.127:27017/test

Or like this if the auth-database is not the same as the chosen database:

mongodb://user:pass@192.168.0.127:27017/test?authSource=otherdb

However, I've not checked if this second form works with this driver.

UNIcodeX commented 4 years ago

What I'm trying to do is use Mongo with Jester for a REST API. I've got two issues. 1) With known working credentials in the newAsyncMongoWithURI method, nimongo says I must be authenticated to do operations on the database. 2) Jester does not know how to handle Bson in the response. Perhaps a toJson method in the nimongo or bson libraries would be good for this.

There may be (probably is) a better way of doing this, so if you're aware of it, please advise.

At-ing @dom96 in case he has some insight into this.

Getting the following error when removing the Jester portion:

(ok: false, n: 0, err: "command insert requires authentication", inserted_ids: @[{"$oid": "5ee0fdfa56670000000020e9"}], bson: {
    "ok" : 0.0,
    "errmsg" : "command insert requires authentication",
    "code" : 13,
    "codeName" : "Unauthorized"
})

It looks like from the examples that using the URI method would auth on connection. Is this not correct?

Building the following with nim c -r -d:release -d:danger --threads:on testSrv.nim

import strformat
import jester
import nimongo/mongo
import nimongo/bson

var
  user = "testUser"
  pass = "testPass"
  db   = "test"
  m: AsyncMongo = newAsyncMongoWithURI(fmt"mongodb://{user}:{pass}@192.168.0.127/{db}?authSource=admin")
  coll = m["test"]["test"]

if not waitFor m.connect():
  echo "Could not connect."

discard waitFor coll.insert(%*{"testKey": "test"})

routes:
  get "/":
    let res = waitFor coll.find(%*{}).all()
    resp res

runForever()

Jester's error message

Error: type mismatch: got <seq[Bson]>
but expected one of:
template resp(code: HttpCode): typed
  first type mismatch at position: 1
  required type for code: HttpCode
  but expression 'res' is of type: seq[Bson]
template resp(code: HttpCode; content: string;
             contentType = "text/html;charset=utf-8"): typed
  first type mismatch at position: 1
  required type for code: HttpCode
  but expression 'res' is of type: seq[Bson]
template resp(code: HttpCode; headers: openArray[tuple[key, value: string]];
             content: string): typed
  first type mismatch at position: 1
  required type for code: HttpCode
  but expression 'res' is of type: seq[Bson]
template resp(content: JsonNode): typed
  first type mismatch at position: 1
  required type for content: JsonNode
  but expression 'res' is of type: seq[Bson]
template resp(content: string; contentType = "text/html;charset=utf-8"): typed
  first type mismatch at position: 1
  required type for content: string
  but expression 'res' is of type: seq[Bson]
JohnAD commented 4 years ago

The Jester part is fairly straightforward. The resp template only allows for a few parameter types. It does not support JSON or BSON, at least not directly. It is generally used with a string. So, converting the parameter passed into res into a string will put the data into the web response.

To pass JSON or XML in a RESTful fashion, here is an snippet of code I used for generating a RSS feed:

routes:
  get "/category/techpodcast/feed/":
    var db = getNextConnection()
    data["itemList"] = read_podCastItemList_recentFifteen(db)
    resp Http200, rssPodcastXML(data), "application/rss+xml"

My rssPodcastXML function returns a string of serialized XML.

(This particular code used mongopool rather than nimongo, but the idea is very similar.)