The canvas project fulfills the requirements of the Sketch Challenge as it will be explained below.
- The canvas project has an idempotent RESTful API. That means, if the system receives a duplicate request it will not fail the second time, it will just be ignored.
- Since only the server part of the challenge is being implemented it was required for the server to actually render the ASCII image. However, in a real client-server scenario the rendering part of the process, usually the most expensive one, could be left for the client side. That way the load in the server side would be smaller overall.
- cmd/canvas: contains the main executable of the project.
- config: contains the general configuration of the project. It follows the 12 factor configuration design.
- devops: contains the configuration for all related matters that are outside the project scope, but are required for it be run.
- devops/db/migrations: contains the migrations required to be run in the DB that wants to be used to store the project information.
- internal: contains the Domain Driven Design approach to implement the requirements of the Sketch Challenge.
- internal/app: contains the application layer, it uses Command Query Separation (CQS) to implement the use cases for the project.
- internal/domain: contains the domain layer.
- internal/infra/ascii: contains the ASCII renderer used by the project to transform a canvas into an ASCII representation of it.
- internal/infra/http: contains the HTTP handlers for the endpoints that will use the command and query handlers from the application layer.
- internal/infra/sql: contains the SQL repositories used to store the canvas information.
The following dependencies are required for the project to be executed. make
, docker
, docker-compose
, and go
.
First step to run the project binary you need to start the DB and run the migrations stored in the devops/db/migrations
folder. In order to do that you need to run:
make start-infra
Now that the DB is up and running you can start the execution of the project binary:
make run
You can stop the DB without losing its contents with the following:
make stop-infra
Alternatively, you can also remove all the content of the DB with:
make remove-infra
Besides the mandatory dependencies to run the project we will need the following extra dependencies to run test and run linting checks in the project. golangci-lint
, and moq
. They can be installed with the following:
make tools
To run the linting checks it is similar to the previous command:
make lint
In order to run the unit test you just need the following command:
make test
Before running the integration test you need the DB to be up and running. Please check the Start the DB
section above.
make test-integration
As mentioned above the project follows the 12 factor configuration design. Therefore, it uses environment variables in order to configure several aspects of the project:
CANVAS_HEIGHT
: sets the default height of the canvases created.CANVAS_WIDTH
: sets the default width of the canvases created.HOST
: sets the host name to listen for HTTP requests.PORT
: sets the port to listen for HTTP requests.DB_URL
: sets the connection URL for the DB (expects it to be PostgreSQL).DB_SSL_MODE
: sets the SSL mode for the DB connection.DB_BINARY_PARAMETERS
: sets the binary parameters for the DB connection.
By sending a POST request to the /canvas
endpoint with a body containing a JSON with the following structure:
{
"id": "02d1170b-67ce-4d19-ae99-acc9ef03c808"
}
$ curl -i -X POST "http://localhost:8080/canvas" -d '{"id":"02d1170b-67ce-4d19-ae99-acc9ef03c808"}'
HTTP/1.1 201 Created
Location: http://localhost:8080/canvas/02d1170b-67ce-4d19-ae99-acc9ef03c808
Date: Mon, 17 May 2021 13:13:18 GMT
Content-Length: 0
By sending a POST request to the /canvas/{canvasID}
endpoint with a JSON body with the following structure:
Note: {canvasID}
needs to be replaced by the ID of the canvas where you want to draw the rectangle
{
"type": "draw_rectangle",
"rectangle": {
"id": "2fb51cca-c789-4938-9d66-948c16a4d42f",
"point": {
"x": 5,
"y": 5
},
"height": 3,
"width": 5,
"filler": "X",
"outline": "0"
}
}
$ curl -i -X POST "http://localhost:8080/canvas/02d1170b-67ce-4d19-ae99-acc9ef03c808" -d '{"type":"draw_rectangle","rectangle":{"id":"2fb51cca-c789-4938-9d66-948c16a4d42f","point":{"x":5,"y":5},"height":3,"width":5,"filler":"X","outline":"0"}}'
HTTP/1.1 200 OK
Date: Mon, 17 May 2021 13:16:25 GMT
Content-Length: 0
By sending a POST request to the /canvas/{canvasID}
endpoint with a JSON body with the following structure:
Note: {canvasID}
needs to be replaced by the ID of the canvas where you want to perform the flood fill operation
{
"type": "add_fill",
"fill": {
"id": "2c2daf0d-97b1-4274-a9ca-06d3c7b167cf",
"point": {
"x": 0,
"y": 0
},
"filler": "-"
}
}
$ curl -i -X POST "http://localhost:8080/canvas/02d1170b-67ce-4d19-ae99-acc9ef03c808" -d '{"type":"add_fill","fill":{"id":"2c2daf0d-97b1-4274-a9ca-06d3c7b167cf","point":{"x":0,"y":0},"filler":"-"}}'
HTTP/1.1 200 OK
Date: Mon, 17 May 2021 13:19:42 GMT
Content-Length: 0
By sending a GET request to the /canvas/{canvasID}
you will receive an ASCII rendering of the canvas as a response.
Note: {canvasID}
needs to be replaced by the ID of the canvas that you want to render
$ curl "http://localhost:8080/canvas/02d1170b-67ce-4d19-ae99-acc9ef03c808"
--------------.......-----------
--------------.......-----------
--------------.......-----------
00000000------.......-----------
0 0------.......-----------
0 XXXXX----.......-----------
00000XXXXX----------------------
-----XXXXX----------------------
--------------------------------
--------------------------------
--------------------------------
--------------------------------