-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API for Asset CRUD Operations and Authentication Middleware #14
Open
petpalioudakis
wants to merge
1
commit into
GlobalWebIndex:main
Choose a base branch
from
petpalioudakis:pp/pr-for-platform-go-challenge
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+679
−18
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Dependency directories (remove the comment below if you are using dep) | ||
# vendor/ | ||
|
||
# Compiled Object files, Static and Dynamic libs (remove the comment below if you are using go modules) | ||
*.o | ||
*.a | ||
*.lo | ||
*.la | ||
*.os | ||
*.so | ||
*.so.* | ||
*.dylib | ||
*.test | ||
*.prof | ||
*.exe | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
FROM golang:1.22.3-bullseye | ||
Check failure on line 1 in Dockerfile Wiz GWI / Wiz IaC ScannerMissing User Instruction
Raw output
Check notice on line 1 in Dockerfile Wiz GWI / Wiz IaC ScannerHealthcheck Instruction Missing
Raw output
|
||
# Set the Current Working Directory inside the container | ||
WORKDIR /app | ||
|
||
# Copy the source from the current directory to the Working Directory inside the container | ||
COPY . . | ||
|
||
# Download all the dependencies | ||
RUN go mod download | ||
|
||
# Install the package | ||
RUN go build -o main . | ||
|
||
# This container exposes port 8080 to the outside world | ||
EXPOSE 8080 | ||
|
||
# Run the executable | ||
CMD ["./main"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,163 @@ | ||
# GlobalWebIndex Engineering Challenge | ||
# User Favorites API | ||
|
||
## Introduction | ||
This is a sample Go application that provides an API for managing user favorites. Users can register, login, and manage their favorite assets (charts, insights, and audiences). The API uses JWT for authentication. | ||
|
||
This challenge is designed to give you the opportunity to demonstrate your abilities as a software engineer and specifically your knowledge of the Go language. | ||
## Project Structure | ||
|
||
On the surface the challenge is trivial to solve, however you should choose to add features or capabilities which you feel demonstrate your skills and knowledge the best. For example, you could choose to optimise for performance and concurrency, you could choose to add a robust security layer or ensure your application is highly available. Or all of these. | ||
``` | ||
user-favorites-api/ | ||
├── Dockerfile | ||
├── docker-compose.yml | ||
├── go.mod | ||
├── go.sum | ||
├── handlers/ | ||
│ └── handlers.go | ||
├── main.go | ||
├── models/ | ||
│ └── models.go | ||
├── router/ | ||
│ └── router.go | ||
├── store/ | ||
│ └── store.go | ||
├── middleware/ | ||
│ └── jwt.go | ||
├── db_scripts/ | ||
│ └── dbsetup.sql | ||
└── README.md | ||
``` | ||
|
||
Of course, usually we would choose to solve any given requirement with the simplest possible solution, however that is not the spirit of this challenge. | ||
## Setup | ||
|
||
## Challenge | ||
### Prerequisites | ||
|
||
Let's say that in GWI platform all of our users have access to a huge list of assets. We want our users to have a peronal list of favourites, meaning assets that favourite or “star” so that they have them in their frontpage dashboard for quick access. An asset can be one the following | ||
* Chart (that has a small title, axes titles and data) | ||
* Insight (a small piece of text that provides some insight into a topic, e.g. "40% of millenials spend more than 3hours on social media daily") | ||
* Audience (which is a series of characteristics, for that exercise lets focus on gender (Male, Female), birth country, age groups, hours spent daily on social media, number of purchases last month) | ||
e.g. Males from 24-35 that spent more than 3 hours on social media daily. | ||
- Docker | ||
- Docker Compose | ||
|
||
Build a web server which has some endpoint to receive a user id and return a list of all the user’s favourites. Also we want endpoints that would add an asset to favourites, remove it, or edit its description. Assets obviously can share some common attributes (like their description) but they also have completely different structure and data. It’s up to you to decide the structure and we are not looking for something overly complex here (especially for the cases of audiences). There is no need to have/deploy/create an actual database although we would like to discuss about storage options and data representations. | ||
### Running the Application | ||
|
||
Note that users have no limit on how many assets they want on their favourites so your service will need to provide a reasonable response time. | ||
1. Ensure you have Docker and Docker Compose installed. | ||
2. Build and start the application using Docker Compose: | ||
|
||
A working server application with functional API is required, along with a clear readme.md. Useful and passing tests would be also be viewed favourably | ||
```sh | ||
docker-compose up --build --remove-orphans | ||
``` | ||
|
||
It is appreciated, though not required, if a Dockerfile is included. | ||
This command will build the Go application image, start the PostgreSQL database, and then start the Go application. The application will be available at `http://localhost:8080`, and the PostgreSQL database will be available at `localhost:5432` with the credentials specified. | ||
|
||
## Submission | ||
## API Endpoints | ||
|
||
Just create a fork from the current repo and send it to us! | ||
### User Registration | ||
|
||
Good luck, potential colleague! | ||
- **URL:** `/register` | ||
- **Method:** `POST` | ||
- **Request Body:** | ||
|
||
```json | ||
{ | ||
"username": "john_doe", | ||
"email": "[email protected]", | ||
"password": "password123" | ||
} | ||
``` | ||
|
||
- **Sample Request:** | ||
|
||
```sh | ||
curl -X POST http://localhost:8080/register -d '{"username":"john_doe","email":"[email protected]","password":"password123"}' -H "Content-Type: application/json" | ||
``` | ||
|
||
### User Login | ||
|
||
- **URL:** `/login` | ||
- **Method:** `POST` | ||
- **Request Body:** | ||
|
||
```json | ||
{ | ||
"username": "john_doe", | ||
"password": "password123" | ||
} | ||
``` | ||
|
||
- **Sample Request:** | ||
|
||
```sh | ||
curl -X POST http://localhost:8080/login -d '{"username":"john_doe","password":"password123"}' -H "Content-Type: application/json" | ||
``` | ||
|
||
- **Response:** | ||
|
||
```json | ||
{ | ||
"token": "your_jwt_token_here" | ||
} | ||
``` | ||
|
||
### Get User Favorites | ||
|
||
- **URL:** `/api/favorites/{userID}` | ||
- **Method:** `GET` | ||
- **Headers:** `Authorization: Bearer your_jwt_token_here` | ||
- **Sample Request:** | ||
|
||
```sh | ||
curl -H "Authorization: Bearer your_jwt_token_here" http://localhost:8080/api/favorites/1 | ||
``` | ||
|
||
### Add Favorite | ||
|
||
- **URL:** `/api/favorites/{userID}` | ||
- **Method:** `POST` | ||
- **Headers:** `Authorization: Bearer your_jwt_token_here` | ||
- **Request Body:** | ||
|
||
```json | ||
{ | ||
"id": "1", | ||
"type": "chart", | ||
"description": "Test Chart", | ||
"data": "Sample Data" | ||
} | ||
``` | ||
|
||
- **Sample Request:** | ||
|
||
```sh | ||
curl -X POST -H "Authorization: Bearer your_jwt_token_here" -d '{"id":"1","type":"chart","description":"Test Chart","data":"Sample Data"}' -H "Content-Type: application/json" http://localhost:8080/api/favorites/1 | ||
``` | ||
|
||
### Remove Favorite | ||
|
||
- **URL:** `/api/favorites/{userID}/{assetID}` | ||
- **Method:** `DELETE` | ||
- **Headers:** `Authorization: Bearer your_jwt_token_here` | ||
- **Sample Request:** | ||
|
||
```sh | ||
curl -X DELETE -H "Authorization: Bearer your_jwt_token_here" http://localhost:8080/api/favorites/1/1 | ||
``` | ||
|
||
### Edit Favorite | ||
|
||
- **URL:** `/api/favorites/{userID}/{assetID}` | ||
- **Method:** `PUT` | ||
- **Headers:** `Authorization: Bearer your_jwt_token_here` | ||
- **Request Body:** | ||
|
||
```json | ||
{ | ||
"description": "Updated Chart Description", | ||
"data": "Updated Sample Data" | ||
} | ||
``` | ||
|
||
- **Sample Request:** | ||
|
||
```sh | ||
curl -X PUT -H "Authorization: Bearer your_jwt_token_here" -d '{"description":"Updated Chart Description","data":"Updated Sample Data"}' -H "Content-Type: application/json" http://localhost:8080/api/favorites/1/1 | ||
``` | ||
|
||
## Environment Variables | ||
|
||
- `DATABASE_URL`: The URL of the PostgreSQL database. Example: `postgresql://user_favorites_user:mysecretpassword@db:5432/user_favorites_db` | ||
- `SECRET_KEY`: The secret key used for signing JWT tokens. It should be a long and random string. Example: `my_super_secret_key_123` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
CREATE TABLE IF NOT EXISTS users ( | ||
id SERIAL PRIMARY KEY, | ||
username VARCHAR(50) NOT NULL UNIQUE, | ||
email VARCHAR(100) NOT NULL, | ||
password TEXT NOT NULL, | ||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP | ||
); | ||
CREATE TABLE IF NOT EXISTS assets ( | ||
id SERIAL PRIMARY KEY, | ||
user_id INT NOT NULL, | ||
asset_id VARCHAR(255) NOT NULL, | ||
type VARCHAR(50) NOT NULL, | ||
description TEXT NOT NULL, | ||
data TEXT NOT NULL, | ||
FOREIGN KEY (user_id) REFERENCES users(id) | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
services: | ||
db: | ||
image: postgres:latest | ||
environment: | ||
POSTGRES_DB: user_favorites_db | ||
POSTGRES_USER: user_favorites_user | ||
POSTGRES_PASSWORD: mysecretpassword | ||
volumes: | ||
- db_data:/var/lib/postgresql/data | ||
- ./db_scripts:/docker-entrypoint-initdb.d | ||
ports: | ||
- "5432:5432" | ||
|
||
app: | ||
build: . | ||
environment: | ||
DATABASE_URL: postgresql://user_favorites_user:mysecretpassword@db:5432/user_favorites_db | ||
SECRET_KEY: mysecretkey | ||
ports: | ||
- "8080:8080" | ||
depends_on: | ||
- db | ||
|
||
volumes: | ||
db_data: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module user-favorites-api | ||
|
||
go 1.22.3 | ||
|
||
require ( | ||
github.com/dgrijalva/jwt-go v3.2.0+incompatible | ||
Check failure on line 6 in go.mod Wiz GWI / Wiz Vulnerability Scannergithub.com/dgrijalva/jwt-go:3.2.0+incompatible
|
||
github.com/gorilla/mux v1.8.1 | ||
github.com/jackc/pgx/v5 v5.6.0 | ||
golang.org/x/crypto v0.23.0 | ||
) | ||
|
||
require ( | ||
github.com/jackc/pgpassfile v1.0.0 // indirect | ||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect | ||
github.com/jackc/puddle/v2 v2.2.1 // indirect | ||
golang.org/x/sync v0.1.0 // indirect | ||
golang.org/x/text v0.15.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | ||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= | ||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= | ||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= | ||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= | ||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= | ||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= | ||
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= | ||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= | ||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= | ||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= | ||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= | ||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= | ||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= | ||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job with the readme, very descriptive 👍