Skip to content

Cattle Disease Detection Endpoint & ML Model Deployments, with microservices architecture. Created using Node, Express, Firestore, Cloud Storage, Cloud Run, Docker.

Notifications You must be signed in to change notification settings

PeduliTernak/CloudComputing-Node-API

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

59 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PeduliTernak - Node.js Backend

This repository contains the Node.js backend for the PeduliTernak project, encompassing implementation of public endpoints gateway, database connection, and user administration. The backend allows users to create an account and detect disease in cattle (perform image recognition and get survey prediction) using API request methods.

How it works

This application is connected to the Firestore Database, Cloud Storage, and Cloud Run microservice.

When a client makes prediction requests, this application synchronously sends requests to the private Cloud Run microservice to perform recognition (because the ML Models are deployed there). The results are then stored in the database and returned to the client as a response.

Cloud Architecture Design

more: diagram

How to Use

  1. Go to Python-Flask Microservice, start the Flask application, and get the Base URL

  2. Create and place Firestore, Cloud Storage, and Cloud Run service account key file in the root directory

    Roles:

    • Firestore: Cloud Datastore User
    • Cloud Storage: Cloud Storage Object User
    • Cloud Run: Cloud Run Invoker (role applied to the Python-Flask Microservice as a service identity)

    Note: Cloud Run Invoker service account is optional, in case you do not want to make the Python-Flask Microservice private

  3. Add this values to Environment Variables or file .env

    PROJECT_ID=your-project-id
    FIRESTORE_SERVICE_ACCOUNT_KEY_FILE=firestore-sa.json
    CLOUD_STORAGE_SERVICE_ACCOUNT_KEY_FILE=cloudStorage-sa.json
    CLOUD_RUN_INVOKER_SERVICE_ACCOUNT_KEY_FILE=cloudRunInvoker-sa.json
    BUCKET=bucket-name
    SECRET=something-secret
    PREDICTION_MICRO_SERVICE_URL=http://flask-base-url.com/

    Note:

    • the value of PREDICTION_MICRO_SERVICE_URL is the Base URL from step 1
    • CLOUD_RUN_INVOKER_SERVICE_ACCOUNT_KEY_FILE is optional
  4. Start the application

    npm install
    npm start

Deployment

  1. You needs to deploy Python-Flask Microservice first, and get the Base URL

  2. Do all things on the How to Use section (except "Start the application" section)

  3. Build the Docker image and run the Docker container

    docker build -t node-api .
    docker run -p 8080:8080 -d node-api

    or Deploy to Cloud Run by configuring the cloudbuild.yaml and .gcloudignore, then submit it

    gcloud builds submit --config=cloudbuild.yaml

Testing

  1. Do all things on the How to Use section (except npm start)

  2. Add test values to Environment Variables or file .env (or just keep the same values as non-testing variables above)

    TEST_PROJECT_ID=test-gcp-capstone
    TEST_FIRESTORE_SERVICE_ACCOUNT_KEY_FILE=test-firestore-sa.json
    TEST_CLOUD_STORAGE_SERVICE_ACCOUNT_KEY_FILE=test-cloudStorage-sa.json
    TEST_CLOUD_RUN_INVOKER_SERVICE_ACCOUNT_KEY_FILE=cloudRunInvoker-sa.json
    TEST_BUCKET=test-bucket-name
  3. Place an image on the tests/ directory named image.jpg (to perform image recognition/prediction testing)

  4. Run the tests

    npm test

API Documentation

Summary

Base URL: https://node-api-74e64w7rga-et.a.run.app

Route HTTP Method Description Token Required?
/api/register POST Sign up a new user -
/api/login POST Login user -
/api/user GET Get user data Yes
/api/user PUT Change user data Yes
/api/user DELETE Delete user and all prediction history Yes
/api/prediction POST Predict the image and save it to database Yes
/api/prediction GET Get all the user's prediction history Yes
/api/prediction/:id GET Get one prediction history by id Yes
/api/prediction/:id DELETE Delete one prediction history by id Yes

tip: just use crtl+f

Token Authorization

You will receive the token after succesfully request to /api/register or /api/login.

Usage

Put the token in the Header with Authorization key and Bearer <token> value.

{
  "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Otherwise, the request will response 401 Unauthorized

{
  "status": false,
  "message": "unauthorized access"
}


Endpoints (Login, Register)

POST /api/register - Sign up a new user

Request
  • Method: POST
  • Path: /api/register
  • Body:
    {
      "username": "john_doe",
      "name": "John Doe",
      "noTelepon": "6285123456",
      "password": "password123"
    }
Response
  • Status: 200 OK

    {
      "status": true,
      "message": "register success",
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "user": {
        "username": "john_doe",
        "name": "John Doe",
        "noTelepon": "6285123456"
      }
    }
  • Status: 400 Bad Request

    {
      "status": false,
      "message": "invalid request argument"
    }
  • Status: 400 Bad Request

    • Password must at least 8 characters

    • Password must be part of the ASCII character

      {
        "status": false,
        "message": "invalid password"
      }
  • Status: 400 Bad Request

    • Phone number must starts with 62

    • Phone number minimum length must be to 9 characters

    • Phone number maximum length must be to 15 characters

      {
        "status": false,
        "message": "invalid phone number"
      }
  • Status: 409 Conflict

    {
      "status": false,
      "message": "username is already exist"
    }
  • Status: 409 Conflict

    {
      "status": false,
      "message": "noTelepon is already exist"
    }

POST /api/login - Login user

Request
  • Method: POST
  • Path: /api/login
  • Body:
    {
      "username": "john_doe",
      "password": "password123"
    }
    or
    {
      "noTelepon": "6285123456",
      "password": "password123"
    }
Response
  • Status: 200 OK

    {
      "status": true,
      "message": "login success",
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "user": {
        "username": "john_doe",
        "name": "John Doe",
        "noTelepon": "6285123456"
      }
    }
  • Status: 400 Bad Request

    {
      "status": false,
      "message": "invalid request argument"
    }
  • Status: 401 Unauthorized

    {
      "status": false,
      "message": "invalid username"
    }
  • Status: 401 Unauthorized

    {
      "status": false,
      "message": "invalid noTelepon"
    }
  • Status: 401 Unauthorized

    {
      "status": false,
      "message": "invalid password"
    }


Endpoints (User)

GET /api/user - Get user data

Request
  • Method: GET
  • Path: /api/user
Response
  • Status: 200 OK
    {
      "status": true,
      "user": {
        "username": "john_doe",
        "name": "John Doe",
        "noTelepon": "6285123456"
      }
    }

PUT /api/user - Change user data

Request
  • Method: PUT
  • Path: /api/user
  • Body: (no need to specify all fields)
    {
      "name": "Updated Name",
      "noTelepon": "6285123456",
      "password": "new_password"
    }
Response
  • Status: 200 OK

    {
      "status": true,
      "message": "user data updated successfully",
      "user": {
        "username": "john_doe",
        "name": "Updated Name",
        "noTelepon": "6285123456"
      }
    }
  • Status: 400 Bad Request

    {
      "status": false,
      "message": "invalid request argument"
    }
  • Status: 409 Conflict

    {
      "status": false,
      "message": "noTelepon is already exist"
    }

DELETE /api/user - Delete user and all prediction history

Request
  • Method: DELETE
  • Path: /api/user
Response
  • Status: 204 No Content


Endpoints (Prediction)

POST /api/prediction - Predict the image and save it to the database

Request
  • Method: POST

  • Path: /api/prediction

  • Body:

    • Form-Data with a single file field named file
    • The file must be part of image/* mime types (an image like .jpg, .png)
    • Maximum file size is 5 MB

    and

    • Form-Data with a string of list (matrix) of gejala penyakit field named gejala_matrix

      "file": image.jpg
      "gejala_matrix": "[0, 0, 0, 0, 1, 1, 0, ...]"
Response
  • Status: 200 OK

    Prediction result can be 0 or more.

    {
      "status": true,
      "prediction": {
        "id": "john_doe-uniqueId",
        "imageUrl": "https://storage.googleapis.com/bucketName/image.jpg",
        "result": {
          "penyakit": ["Masitis", "Penyakit 2"],
          "penanganan": [
            "Menjaga kandang untuk tetap bersih. Memakai antiseptik ...",
            "Deskripsi penanganan dari penyakit 2"
          ]
        }
      }
    }
  • Status: 400 Bad Request

    {
      "status": false,
      "message": "invalid request argument or file format"
    }

GET /api/prediction - Get all the user's prediction history

Request
  • Method: GET
  • Path: /api/prediction
Response
  • Status: 200 OK
    {
      "status": true,
      "predictions":
        [
          {
            "id": "john_doe-uniqueId",
            "imageUrl": "https://storage.googleapis.com/bucketName/image.jpg",
            "result":
              {
                "penyakit": ["Masitis", "Penyakit 2"],
                "penanganan":
                  [
                    "Menjaga kandang untuk tetap bersih. Memakai antiseptik ...",
                    "Deskripsi penanganan untuk penyakit 2",
                  ],
              },
          },
          {
            "id": "john_doe-uniqueId2",
            "imageUrl": "https://storage.googleapis.com/bucketName/image2.jpg",
            "result":
              {
                "penyakit": ["Penyakit 1"],
                "penanganan": ["Deskripsi penanganan untuk penyakit 1"],
              },
          },
          {
            "id": "john_doe-uniqueId3",
            "imageUrl": "https://storage.googleapis.com/bucketName/image3.jpg",
            "result": { "penyakit": [], "penanganan": [] },
          },
          ... another results,
        ],
    }

GET /api/prediction/:id - Get one prediction history by id

Request
  • Method: GET
  • Path: /api/prediction/:id
Response
  • Status: 200 OK

    {
      "status": true,
      "prediction": {
        "id": "john_doe-uniqueId",
        "imageUrl": "https://storage.googleapis.com/bucketName/image.jpg",
        "result": {
          "penyakit": ["Masitis", "Penyakit 2"],
          "penanganan": [
            "Menjaga kandang untuk tetap bersih. Memakai antiseptik ...",
            "Deskripsi penanganan dari penyakit 2"
          ]
        }
      }
    }
  • Status: 404 Not Found

    {
      "status": false,
      "message": "prediction id is not found"
    }

DELETE /api/prediction/:id - Delete one prediction history by id

Request
  • Method: DELETE
  • Path: /api/prediction/:id
Response
  • Status: 204 No Content

  • Status: 404 Not Found

    {
      "status": false,
      "message": "prediction id is not found"
    }

About

Cattle Disease Detection Endpoint & ML Model Deployments, with microservices architecture. Created using Node, Express, Firestore, Cloud Storage, Cloud Run, Docker.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages