duct 2021-01-07

@roelof has joined the channel

Good morning

Im trying to follow the tutorial on duct

and have to add something for migrations

so I did change the file to this :

{:duct.profile/base
 {:duct.core/project-ns todo

  :duct.router/ataraxy
  {:routes {[:get "/"] [:todo.handler/index]}}
   [:duct.handler.static/ok :todo.handler/index]
 {:body {:entries "/entries"}}}
 
:duct.migrator/ragtime
{:migrations [#ig/ref :todo.migration/create-entries]}

[:duct.migrator.ragtime/sql :todo.migration/create-entries]
{:up ["CREATE TABLE entries (id INTEGER PRIMARY KEY, content TEXT)"]
 :down ["DROP TABLE entries"]}
 
 :duct.profile/dev   #duct/include "dev"
 :duct.profile/local #duct/include "local"
 :duct.profile/prod  {}

 :duct.module/logging {}
 :duct.module.web/api
 {}
 :duct.module/sql
 {}}

but now I see this error message

Execution error (IllegalArgumentException) at clojure.java.jdbc/get-connection (jdbc.clj:292).
db-spec null is missing a required parameter

I think you at least need to move :duct.migrator/ragtime and [:duct.migrator.ragtime/sql :todo.migration/create-entries] into the :duct.profile/base map

(They are one level higher, in the module level)

I'm not sure if that'll solve everything though, but that needs to be fixed

hmm, when I check the { it looks the code is inside the map

all the code seems to be in the map

or I misunderstood you

Here is a fixed version:

{:duct.profile/base
 {:duct.core/project-ns todo

  :duct.router/ataraxy
  {:routes {[:get "/"] [:todo.handler/index]}}

  [:duct.handler.static/ok :todo.handler/index]
  {:body {:entries "/entries"}}

  :duct.migrator/ragtime
  {:migrations [#ig/ref :todo.migration/create-entries]}

  [:duct.migrator.ragtime/sql :todo.migration/create-entries]
  {:up ["CREATE TABLE entries (id INTEGER PRIMARY KEY, content TEXT)"]
   :down ["DROP TABLE entries"]}}

 :duct.profile/dev   #duct/include "dev"
 
 :duct.profile/local #duct/include "local"
 
 :duct.profile/prod  {}
 
 :duct.module/logging {}
 
 :duct.module.web/api {}
 
 :duct.module/sql {}}

the two keys I mentioned are now inside of the map of :duct.profile/base , not in the top level map

(You can see the difference in indentation)

thanks, but if I copy/paste your code the layout is messed up

Because of Slack you mean?

it looks now this in vs code :

{:duct.profile/base
 {:duct.core/project-ns todo  :duct.router/ataraxy
  {:routes {[:get "/"] [:todo.handler/index]}}  [:duct.handler.static/ok :todo.handler/index]
  {:body {:entries "/entries"}}  :duct.migrator/ragtime
  {:migrations [#ig/ref :todo.migration/create-entries]}  [:duct.migrator.ragtime/sql :todo.migration/create-entries]
  {:up ["CREATE TABLE entries (id INTEGER PRIMARY KEY, content TEXT)"]
   :down ["DROP TABLE entries"]}} :duct.profile/dev   #duct/include "dev" :duct.profile/local #duct/include "local" :duct.profile/prod  {} :duct.module/logging {} :duct.module.web/api {} :duct.module/sql {}}

Yeah that's not good lol

that is better

Do you see what's different now?

yep, on my old code everything was intented the same

Hopefully it'll fix your error. Here's a small overview about the difference between base / profile / module configs https://github.com/duct-framework/duct/wiki/Configuration#duct-base-profiles-and-modules

hmm maybe a error in the tutorial

First, add a new POST route:

:duct.router/ataraxy
{:routes
 {[:get "/"]        [:todo.handler/index]
  [:get "/entries"] [:todo.handler.entries/list]

  [:post "/entries" {{:keys [description]} :body-params}]
  [:todo.handler.entries/create description]}}

The new Ataraxy route not only matches the method and URI of the request, it also destructures the request body and places the description of the todo entry into the result.

When we come to write the associated handler, we need some way of getting the information from the result. Ataraxy places the result into the :ataraxy/result key on the request map, so we can destructure the request to find the description of the new entry:

[:duct.handler.sql/insert :todo.handler.entries/create]
{:request {[_ description] :ataraxy/result}
 :sql     ["INSERT INTO entries (description) VALUES (?)" description]}

must the last line not be :duct.handler.sql/create ....

because of this error message :

Missing definitions for refs: :todo.handlers.entries.create

Can you link the tutorial?

Do you have [duct/handler.sql "0.4.0"] as a dependency in project.clj?

Also I've never used sql handlers, I feel that it doesn't really give me enough control over my handlers

:dependencies [[org.clojure/clojure "1.10.0"]
                 [duct/core "0.7.0"]
                 [duct/handler.sql "0.4.0"]
                 [duct/module.logging "0.4.0"]
                 [duct/module.web "0.7.0"]
                 [duct/module.ataraxy "0.3.0"]
                 [duct/module.sql "0.5.0"]
                 [org.xerial/sqlite-jdbc "3.25.2"]]

Can you show me your config?

you mean project.clj or config.edn ?

Oh I see, you have :todo.handlers.entries.create but I think that should be :todo.handlers.entries/create

The error is saying it can't find a key for :todo.handlers.entries.create, which makes sense

chips, that sort of errors do I overlooked very often

now another problem not related to duct I think

http post :3000/entries description="Write Duct guide"

http: error: ConnectionError: HTTPConnectionPool(host='localhost', port=3000): Max retries exceeded with url: /entries (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7c4f0ff4f0>: Failed to establish a new connection: [Errno 111] Connection refused')) while doing POST request to URL: 

I guess the server isn't started?

hmm, you mean the duct server or the sqlite server

That HTTPie error sounds like it can't connect because it doesn't exist

this is telling me that the duct server is working

user=> (dev)
:loaded

(dev) switches you to the development namespace (`dev.clj`). Afterwards to start the server you have to use (go)

and now the error re appears again

Execution error (ExceptionInfo) at integrant.core/missing-refs-exception (core.cljc:191).
Missing definitions for refs: :todo.handlers.entries/create

finally it worked

maybe after this one look for a tutorial where duct is used to ask a external api

hmmm, and another wierd error:

{:duct.profile/base
 {:duct.core/project-ns todo

  :duct.router/ataraxy
  {:routes {[:get "/"] [:todo.handler/index]
            [:get "/entries"] [:todo.handler.entries/list]

            [:post "/entries" {{:keys [description]} :body-params}]
            [:todo.handler.entries/create description]

            [:get "/entries/" id] [todo.handler.entries/find ^int id]
            [:delete "entries/" id] [todo.handler.entries/destroy ^int id]}}

  [:duct handler.sql/query-one :todo.handler.entries/find]
  {:request {[_ id] :ataraxy/result}
   :sql ["SELECT * FROM entries WHERE id = ?" id]
   :hrefs {:href "entries/{id}"}}

  [:duct.handler.sql/execute :todo.handler.entries/destroy]
  {:request {[_ id] :ataraxy/result}
   :sql ["DELETE FROM entries WHERE id =?" id]}

  [:duct.handler.static/ok :todo.handler/index]
  {:body {:entries "/entries"}}

  [:duct.handler.sql/query :todo.handler.entries/list]
  {:sql ["SELECT * FROM entries"]
   :hrefs {:href "/entries/{id}"}}

  [:duct.handler.sql/insert :todo.handler.entries/create]
  {:request {[_ description] :ataraxy/result}
   :sql     ["INSERT INTO entries (description) VALUES (?)" description]
   :location "entries/{last_insert_rowid}"}

  :duct.migrator/ragtime
  {:migrations [#ig/ref :todo.migration/create-entries]}

  [:duct.migrator.ragtime/sql :todo.migration/create-entries]
  {:up ["CREATE TABLE entries (id INTEGER PRIMARY KEY, description TEXT)"]
   :down ["DROP TABLE entries"]}}

 :duct.profile/dev   #duct/include "dev"
 :duct.profile/local #duct/include "local"
 :duct.profile/prod  {}
 :duct.module/logging {}
 :duct.module.web/api {}
 :duct.module/sql {}}

reset)
:reloading ()
Execution error (AssertionError) at integrant.core/eval3789$fn (core.cljc:64).
Assert failed: (namespace parent)

The error is super cryptic (A bit of an Integrant issue). But I looks like you have a typo here: [:duct handler.sql/query-one :todo.handler.entries/find]

pff changed it

but now see this :

Execution error (AssertionError) at ataraxy.core/parse (core.clj:105).
Assert failed: (valid? routes)

Apparently the syntax isn't correct for :routes

oke, I copied the code from the tutorial and everything is working

oke, done that one

are there more tutorials I can follow to get more familiar with duct ?

There aren't many tutorials sadly. But be sure to understand how Integrant works https://github.com/weavejester/integrant/

âž• 1

Because that's about 90% of what Duct is

Will read that well

and maybe it is then better to write my own toy-project

maybe a piece of a galllery I wanted to build or a part of a crm I have in mind