GlobalWebIndex Engineering Challenge#41
Conversation
alexandros-georgantas
left a comment
There was a problem hiding this comment.
Hello @gtopal 👋 ,
Thanks for taking the time working on this assignment!
Your implementation is complete and straight forward covering various aspects.
I have posted some comments in your PR more as a conversation starter.
To this end, I would appreciate if you find the time to have a look and address my comments!
Thanks,
Alex
| @@ -0,0 +1,11 @@ | |||
| # Start from the official Golang image | |||
| FROM golang:1.21-alpine AS builder | |||
There was a problem hiding this comment.
Could you please explain why you've used this specific version of Go?
There was a problem hiding this comment.
This version is stable, lightweight and reduces the final image size. Moreover, I think it's preferable to use a specific version and not the latest in order not to break anything.
There was a problem hiding this comment.
In principal I agree however this version if I am not mistaken is from 2023 https://go.dev/doc/devel/release#go1.21.0
There was a problem hiding this comment.
ok! Next time I will be aware of not using an obsolete version
| @@ -0,0 +1,175 @@ | |||
| { | |||
There was a problem hiding this comment.
Nice touch providing postman blueprint
| @@ -0,0 +1,298 @@ | |||
| package main | |||
There was a problem hiding this comment.
If you were to provide a bit more structure to this deliverable how you will have done it?
There was a problem hiding this comment.
For sure some points need refactoring for readability and maintainability purposes.
I will:
-
Extract logic into functions:
For example , the creation of the user could go in a seperate function
or
It could be useful also to create a seeder for creating users and assets related to the users and put an appropriate command also inMakefile
Another example could be to create a function for starting the server -
Create a
.env.exampleand also a.envfile to capture environmental variables
For example I noticed that the variablejwtSecretcould be stored in.envasJWT_SECRET -
Create maybe a seperate folder for tests and put there seperate files for testing, one let's say for API calls and one for more general unit tests
-
Put the endpoint calls to a seperate file and the handling logic(functions) to another one.
| return assetID, true | ||
| } | ||
|
|
||
| func setupRoutes() { |
There was a problem hiding this comment.
Cloud you please provide an alternative for the structure of the favorites endpoints (to become more RESTful)?
There was a problem hiding this comment.
Yes sure.
I know it will be better to structure my endpoints like below:
To add:POST /users/{user_id}/favourites
To update: PUT /users/{user_id}/favourites/{asset_id}
To delete: DELETE /users/{user_id}/favourites/{asset_id}
To list: GET /users/{user_id}/favourites
using request parameters like
http://localhost:8080/favourites/remove?asset_id=c217dd2d-1866-43f0-88a5-5550504fe62dis not a good practice
| http.Error(w, "Unauthorized", http.StatusUnauthorized) | ||
| return | ||
| } | ||
| user := store.GetUser(userID) |
There was a problem hiding this comment.
Lets say that someone asks to change from in-memory storage to a proper database approach. Based on this line, how easy is to make this transition?
There was a problem hiding this comment.
I am not sure if I understand correct, but I would change only the implementation of the GetUser
The method signature and usage stay the same. The receiver of GetUser would change to *DBStorage something like func (s *DBStorage) GetUser(id uuid.UUID) *User { ... }
and the implementation should query the DB.
In other words, I would take advantage of using interfaces in order based on my option to change the implementation based on the receiver.
Of course for the DB declaration I should create a service with an image let's say for Postgresql and define also the connection parameters to .env
There was a problem hiding this comment.
Here basically I am more interested to hear your thoughts around D.I. and if it is feasible based on how you've implemented your handlers.
There was a problem hiding this comment.
@alexandros-georgantas As it is , is not feasible cause I have a hard dependency on handlers
I have to define a more flexible approach such as declaring an interface like:
type UserStore interface {
GetUser(id uuid.UUID) *User
}
and then make the handlers depend on UserStore
type Handler struct {
Store UserStore
}
and injecting either an in-memory store or a DB-backed implementation.
| AudienceType = "audience" | ||
| ) | ||
|
|
||
| type Asset interface { |
Hello @alexandros-georgantas , thanks for the feedback and your time looking my PR. I will reply as soon as possible. |
Description
My deliverable for the GlobalWebIndex Engineering Challenge