Skip to content

Commit

Permalink
Merge pull request #2612 from CrowleyRajapakse/wso2-apk-code-challenge
Browse files Browse the repository at this point in the history
Adding apk code challenge artifacts
  • Loading branch information
CrowleyRajapakse authored Oct 21, 2024
2 parents 1245646 + 68f01be commit 8c36e14
Show file tree
Hide file tree
Showing 7 changed files with 373 additions and 0 deletions.
56 changes: 56 additions & 0 deletions code-challenge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# WSO2 APK Code Challenge ToDo Service

## Docker Image

docker pull sampathrajapakse/todo-service:latest

## Docker Image Creation

Use the above provided docker image or you can build using following commands.

docker buildx create --use

docker buildx inspect --bootstrap

docker buildx build --platform linux/amd64,linux/arm64 -t sampathrajapakse/todo-service:latest --push .

## Deploy in K8s Cluster

kubectl create ns apk

kubectl apply -f k8s-artifacts/deployment.yaml -n apk

## Access the pod locally

kubectl port-forward pod/todo-app-<random-id> 8080:8080 -n apk

## Invoke the services

### Retrieve all to-dos

curl http://localhost:8080/todos

### Create a new to-do

curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{"task": "Buy groceries", "done": false}'

### Retrieve a single to-do

curl http://localhost:8080/todos/1

### Update an existing to-do

curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{"task": "Buy groceries", "done": true}'

### Delete a to-do

curl -X DELETE http://localhost:8080/todos/1

### Register a user with user-reg header

curl -X POST http://localhost:8080/register \
-H "user-reg: sampath"
41 changes: 41 additions & 0 deletions code-challenge/k8s-artifacts/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: todo-app
labels:
app: todo-app
spec:
replicas: 1
selector:
matchLabels:
app: todo-app
template:
metadata:
labels:
app: todo-app
spec:
containers:
- name: todo-app
image: sampathrajapakse/todo-service:latest
ports:
- containerPort: 8080
resources:
limits:
memory: "128Mi"
cpu: "500m"
requests:
memory: "64Mi"
cpu: "250m"
---
apiVersion: v1
kind: Service
metadata:
name: todo-app-service
spec:
selector:
app: todo-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
144 changes: 144 additions & 0 deletions code-challenge/open-api/oas.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
openapi: 3.0.3
info:
title: To-Do API
description: A simple to-do service API
version: 1.0.0
servers:
- url: http://todo-app-service:80
description: Local development server
paths:
/todos:
get:
summary: Retrieve all to-dos
description: Returns a list of all to-do items
responses:
'200':
description: A list of to-do items
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ToDo'
post:
summary: Create a new to-do
description: Adds a new to-do item
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewToDo'
responses:
'201':
description: To-do created successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToDo'
'400':
description: Invalid input
/todos/{id}:
get:
summary: Retrieve a single to-do item
description: Returns the details of a specific to-do item by its ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: The requested to-do item
content:
application/json:
schema:
$ref: '#/components/schemas/ToDo'
'404':
description: To-do not found
put:
summary: Update a to-do item
description: Updates an existing to-do item by its ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewToDo'
responses:
'200':
description: To-do updated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToDo'
'400':
description: Invalid input
'404':
description: To-do not found
delete:
summary: Delete a to-do item
description: Deletes a to-do item by its ID
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'204':
description: To-do deleted successfully
'404':
description: To-do not found
/register:
post:
summary: Register a user
description: Registers a new user and expects a custom header `user-reg`
parameters:
- name: user-reg
in: header
required: true
schema:
type: string
responses:
'201':
description: User registered successfully
'400':
description: Missing or invalid header
components:
schemas:
ToDo:
type: object
properties:
id:
type: integer
description: Unique identifier of the to-do item
task:
type: string
description: The task description
done:
type: boolean
description: Status of the to-do (completed or not)
required:
- id
- task
- done
NewToDo:
type: object
properties:
task:
type: string
description: The task description
done:
type: boolean
description: Status of the to-do (completed or not)
required:
- task
- done
23 changes: 23 additions & 0 deletions code-challenge/todo-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Build Stage
FROM golang:1.22 AS build

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . ./

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# Deployment Stage
FROM alpine:3.19.1

WORKDIR /root/

COPY --from=build /app/main .

# Expose the application port
EXPOSE 8080

CMD ["./main"]
5 changes: 5 additions & 0 deletions code-challenge/todo-app/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/wso2/apk/code-challenge/todo-app

go 1.22.6

require github.com/gorilla/mux v1.8.1
2 changes: 2 additions & 0 deletions code-challenge/todo-app/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
102 changes: 102 additions & 0 deletions code-challenge/todo-app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package main

import (
"encoding/json"
"log"
"net/http"
"strconv"

"github.com/gorilla/mux"
)

type Todo struct {
ID int `json:"id"`
Task string `json:"task"`
Done bool `json:"done"`
}

var todos []Todo
var nextID = 1

// Get all to-dos
func getTodos(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(todos)
}

// Create a new to-do
func createTodo(w http.ResponseWriter, r *http.Request) {
var todo Todo
_ = json.NewDecoder(r.Body).Decode(&todo)
todo.ID = nextID
nextID++
todos = append(todos, todo)
json.NewEncoder(w).Encode(todo)
}

// Get a single to-do by ID
func getTodoByID(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, _ := strconv.Atoi(params["id"])
for _, todo := range todos {
if todo.ID == id {
json.NewEncoder(w).Encode(todo)
return
}
}
http.Error(w, "To-do not found", http.StatusNotFound)
}

// Update a to-do by ID
func updateTodo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, _ := strconv.Atoi(params["id"])
for index, todo := range todos {
if todo.ID == id {
todos = append(todos[:index], todos[index+1:]...)
var updatedTodo Todo
_ = json.NewDecoder(r.Body).Decode(&updatedTodo)
updatedTodo.ID = id
todos = append(todos, updatedTodo)
json.NewEncoder(w).Encode(updatedTodo)
return
}
}
http.Error(w, "To-do not found", http.StatusNotFound)
}

// Delete a to-do by ID
func deleteTodo(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, _ := strconv.Atoi(params["id"])
for index, todo := range todos {
if todo.ID == id {
todos = append(todos[:index], todos[index+1:]...)
json.NewEncoder(w).Encode(todos)
return
}
}
http.Error(w, "To-do not found", http.StatusNotFound)
}

// Register a user
func registerUser(w http.ResponseWriter, r *http.Request) {
regHeader := r.Header.Get("user-reg")
if regHeader == "" {
http.Error(w, "Missing user-reg header", http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte("User registered with header: " + regHeader))
}

func main() {
router := mux.NewRouter()
router.HandleFunc("/todos", getTodos).Methods("GET")
router.HandleFunc("/todos", createTodo).Methods("POST")
router.HandleFunc("/todos/{id}", getTodoByID).Methods("GET")
router.HandleFunc("/todos/{id}", updateTodo).Methods("PUT")
router.HandleFunc("/todos/{id}", deleteTodo).Methods("DELETE")
router.HandleFunc("/register", registerUser).Methods("POST")

log.Fatal(http.ListenAndServe(":8080", router))
}

0 comments on commit 8c36e14

Please sign in to comment.