daas workshop
  • Hands-On experience building a Data as a Service Platform
  • Set Up
    • Creating a Workstation
    • Installing Tools
    • Starting Kafka
    • Congratulations
  • Module I - Overview of the DaaS Pattern
    • Section I - The Overall Pattern
    • Section II - Data Sourcing
    • Section III - Data Provisioning
    • Section IV - Data Consumption
  • Module II - Building a Rust Project
    • Section I - Create a Package
    • Section II - Creating a Library
    • Section III - Creating an Executable
    • Section IV - Creating a Hello World RESTful Endpoint
      • Section IV - manifest
      • Section IV - library
      • Section IV - module
      • Section IV - integrated testing
      • Section IV - executable
  • Module III - Building a RESTful Endpoint for Sourcing Data
    • Section I - Overview
    • Section II - manifest
    • Section III - executable
    • Section IV - starting the service
    • Section V - service testing
  • Module IV - Building a Genesis Microservice for Processing the Sourced Data
    • Section I - Overview
    • Section II - manifest
    • Section III - executable
    • Section IV - starting the service
    • Section V - service testing
  • Module V - Building a Provisioning Microservice
    • Section I - Overview
    • Section II - manifest
    • Section III - executable
    • Section IV - starting the service
    • Section V - adding the business logic
    • Section VI - testing the service
  • Module VI - Building a RESTful Endpoint for Publishing Reporting Data
    • Section I - Overview
    • Section II - manifest
    • Section III - executable
    • Section IV - starting the service
    • Section V - adding the business logic
    • Section VI - testing the service
  • Privacy Design Strategies
  • Further Exploration
Powered by GitBook
On this page

Was this helpful?

  1. Module VI - Building a RESTful Endpoint for Publishing Reporting Data

Section V - adding the business logic

PreviousSection IV - starting the serviceNextSection VI - testing the service

Last updated 3 years ago

Was this helpful?

Now that we know the service is reading the path parameter product we can add our business logic to retrieve the JSON payload.

Add additional use declarations:

use std::{fs, io};
use std::fs::File;
use std::io::prelude::*;
use serde_json::json;
use serde_json::value::Value;

Add a new constant as a global variable

static WORKSPACE_LOCAL_STORAGE: &str = "./workshop_storage";

Include a supportive function after the outside of the main function.

fn extract_product_name(file_path: String) -> String {
    file_path
        .replace(&format!("{}/clothing-", WORKSPACE_LOCAL_STORAGE),"")
        .replace(".json","")
        .replace("_"," ")
}
fn product_file(product_name: String) -> String {
    format!("{}/clothing-{}.json", WORKSPACE_LOCAL_STORAGE, product_name.replace(" ","_")) 
}
fn read_file(file: String) -> Option<Value> {
    let mut file = match File::open(file) {
        Ok(f) => {
            f
        },
        Err(_e) => return None,
    };
    
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    
    Some(serde_json::from_str(&contents).unwrap())
}

Modify the index function with the new business logic.

async fn index(req: HttpRequest) -> HttpResponse {
   let product = req.match_info().get("product").unwrap_or(ALL_PRODUCTS);
    
   let content = match &product {
        &"all" => {
            let mut products = Vec::new();
        
            let entries = fs::read_dir(WORKSPACE_LOCAL_STORAGE).unwrap()
                .map(|res| res.map(|e| e.path()))
                .collect::<Result<Vec<_>, io::Error>>().unwrap();
                
            for entry in entries.iter() {
                let file = entry.to_str().unwrap().to_string();
                let mut obj = read_file(file.clone()).unwrap();
                obj.as_object_mut()
                    .unwrap()
                    .insert("product".to_string(), Value::String(extract_product_name(file)));
                
                products.push(obj);
            }
            
            json!(products).to_string()
        },
        _ => {
            match read_file(product_file(product.to_string())) {
                Some(cntnt) => {
                    cntnt.to_string()
                },
                None => {
                    "Product file missing".to_string()
                },
            }
        },
    };
    
    HttpResponse::build(StatusCode::OK)
        .body(&content)
}

The final reporting.rs file should look like the following:

extern crate actix_web;

use actix_web::{web, App, HttpRequest, HttpServer, HttpResponse};
use actix_web::http::{StatusCode};
use actix_web::middleware::Logger;

use std::{fs, io};
use std::fs::File;
use std::io::prelude::*;
use serde_json::json;
use serde_json::value::Value;

static ALL_PRODUCTS: &str = "all";
static WORKSPACE_LOCAL_STORAGE: &str = "./workshop_storage";

fn extract_product_name(file_path: String) -> String {
    file_path
        .replace(&format!("{}/clothing-", WORKSPACE_LOCAL_STORAGE),"")
        .replace(".json","")
        .replace("_"," ")
}

fn product_file(product_name: String) -> String {
    format!("{}/clothing-{}.json", WORKSPACE_LOCAL_STORAGE, product_name.replace(" ","_")) 
}

fn read_file(file: String) -> Option<Value> {
    let mut file = match File::open(file) {
        Ok(f) => {
            f
        },
        Err(_e) => return None,
    };
    
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    
    Some(serde_json::from_str(&contents).unwrap())
}

async fn index(req: HttpRequest) -> HttpResponse {
    let product = req.match_info().get("product").unwrap_or(ALL_PRODUCTS);
    
   let content = match &product {
        &"all" => {
            let mut products = Vec::new();
        
            let entries = fs::read_dir(WORKSPACE_LOCAL_STORAGE).unwrap()
                .map(|res| res.map(|e| e.path()))
                .collect::<Result<Vec<_>, io::Error>>().unwrap();
                
            for entry in entries.iter() {
                let file = entry.to_str().unwrap().to_string();
                let mut obj = read_file(file.clone()).unwrap();
                obj.as_object_mut()
                    .unwrap()
                    .insert("product".to_string(), Value::String(extract_product_name(file)));
                
                products.push(obj);
            }
            
            json!(products).to_string()
        },
        _ => {
            match read_file(product_file(product.to_string())) {
                Some(cntnt) => {
                    cntnt.to_string()
                },
                None => {
                    "Product file missing".to_string()
                },
            }
        },
    };
    
    HttpResponse::build(StatusCode::OK)
        .body(&content)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    std::env::set_var("RUST_LOG", "actix_web=info");
    env_logger::init();
    
    HttpServer::new(|| {
        App::new()
            .wrap(Logger::default())
            .wrap(Logger::new("%a %{User-Agent}i"))
            .route("/{product}", web::get().to(index))
    })
    .bind("localhost:8001")?
    .run()
    .await
}
reporting.rs