eminetto / clean-architecture-go-v2

Clean Architecture sample
1.28k stars 228 forks source link

Grokking the Clean Architecture API setup process #13

Closed breaker-of-stone closed 2 years ago

breaker-of-stone commented 2 years ago

Hi, excellent exposition of the Clean Architecture concepts - I'm deeply grateful for the articles and repo.

I'm using these as a pathway to learning (and teaching) API construction in Go, however I am having difficulty getting up the first couple of rungs of the knowledge ladder, and I imagine others will face the same difficulties.

I'd appreciate guidance on a few issues we've run into, if you don't mind.

[0] Is the code entirely functional (or merely illustrative in parts)?

[1] When running ./bin/api: README describes API invocations with curl, however result is "Error adding book" or similar, and the api process log produces HTTP 500 errors:

[negroni] 2022-02-09T21:03:38+08:00 | 500 |      59.881538ms | localhost:8080 | GET /v1/book
[negroni] 2022-02-09T21:04:09+08:00 | 500 |      6.736978ms | localhost:8080 | POST /v1/book

I'll assume these are due to issue [2], but is there a simple way to expose more context?

[2] ./bin/search ozzy # produces:

2022/02/09 21:08:51 Error 1045: Access denied for user 'clean_architecture_go_v2'@'localhost'

... which indicates I don't have a database set up. Fair enough, but would have appreciated some guidance before the API curl examples.

[3] It also indicates I should authenticate somehow. Are we relying on HTTP/Basic? Any clues you can offer?

[4] docker-compose.yml indicates a MySQL image might be used. I'll give that a try then. ./ops/db/init.sql seems to be used for database creation. Passwords appear to be created in plain text, so can preload a few - correct?

[5] Are Grafana and Prometheus (a) functionally necessary or (b) valuable for understanding the code's behaviour?

Thx!

breaker-of-stone commented 2 years ago

Re [1], [2] it's not the lack of a database.

mysql> select * from user;
+-------+-------------------+-----------+
| id    | email             | password  |
+-------+-------------------+-----------+
| auser | anemail@gmail.com | apassword |
+-------+-------------------+-----------+

$ curl -u auser:apassword -iX "POST" "http://localhost:8080/v1/user" -H 'Content-Type: application/json'  -H 'Accept: application/json' -d $'{  "email": "ozzy@metal.net",  "first_name": "Ozzy",  "last_name": "Osbourne",  "password": "bateater666"}'
HTTP/1.1 500 Internal Server Error
Access-Control-Allow-Headers: Accept, Authorization, Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Fri, 11 Feb 2022 03:47:41 GMT
Content-Length: 17

Error adding user%

--- and ---
2022/02/11 11:47:41 Error 1045: Access denied for user 'clean_architecture_go_v2'@'localhost' (using password: YES)
[negroni] 2022-02-11T11:47:41+08:00 | 500 |      81.754036ms | localhost:8080 | POST /v1/user

=:-o
breaker-of-stone commented 2 years ago

Answers:

[1] & [2] The database connection has been hijacked by an unrelated MySQL instance. Improvement Suggestions below.

Details:

API authentication errors continue, despite using the (config sourced) credentials which work interactively in the Docker console shell.

ps aux |grep mysql  
    # reveals an obsolete mysqld instance, which is stealing the queries to port 3306.
    # Note that mysql container in Docker indicates in Docker UI that it has attached to port 3306, yet ...
    # Docker log reports (amongst a mass of irrelevant entries):  [Note] Aborted connection 8 to db: 'clean_architecture_go_v2' user: 'clean_architecture_go_v2' host: 'localhost' (Got timeout reading communication packets) - not exactly a definitive error :(

brew services stop mysql
    # confirm with ps, brew services lis,  lanchctl list

In Docker UI restart mysql container.

[6] Next issue: List Users Curl query returns a 500, however the SQL error is more diagnostic:

2022/02/12 11:03:57 In api/handler.user.go/listUsers:26
2022/02/12 11:03:57 ListUsers error:  sql: Scan error on column index 0, name "id": Scan: invalid UUID length: 5
[negroni] 2022-02-12T11:03:57+08:00 | 500 |      10.367251ms | localhost:8080 | GET /v1/user

It turns out that the id is not simply varchar(50) as specified in the initdb.sql script. It contains a UUID that is generated at user creation time. So ...

Curl to create a user. Curl to list users again. Success!

Improvement Suggestions

  1. 'make test' clearly does no database write/read tests. Add some, even if as a new Make target.
  2. the /ping route could be upgraded to a /smoketest function that does an ephemeral database connection test.
  3. MySQL errors are not identified as such - prefix 'Error 1045: Access denied' with a token to indicate message originates from database driver, so it is not mis-perceived as an HTTP auth issue.
  4. Provide a single paragraph description of the engineering architecture - API code, database, Prometheus, Grafana - what feeds what to what, and where to find the logs!

Onward and Downward ! 😧