Configure the Advanced I/O Function
Next, we will begin coding the to-do list application by configuring the function component.
If you have initialized the Advanced I/O function in Java, the functions directory, in this case functions/ToDoList contains:
- The ToDoList.java main function file
- The catalyst-config.json configuration file
- Java library files in the lib directory
- .classpath and .project dependency files
If you have initialized the Advanced I/O function in Node.js, the function's directory, in this case, functions/to_do_list_function contains:
- The index.js main function file
- The catalyst-config.json configuration file
- Node modules
- package.json and package-lock.json dependency files
You will be adding code in the ToDoList.java or index.js file.
The three APIs in the Advanced I/O function that handle the routing between the server and the Data Store are:
- GET /todo: To obtain the to-do list items from the TodoItems table in the Data Store
- POST /todo: To create and save a new list item in the Data Store
- DELETE /todo: To delete a list item from the Data Store
Install Express Framework for Node.js
If you are coding in the Node.js platform, you will need to use the Express framework to perform routing operations. To import the Express package in your function's code, you must install the Express dependency in your system.
To install Express.js iin your local machine, navigate to the function's home directory (functions/to_do_list_function) in your terminal and execute the following command:
$ npm install express --save
This will install the Express module and save the dependencies.
This information will also be updated in the package.json file.
Next, let's add the code in the function file. Copy the Java code and paste it in ToDoList.java in the functions/TodoList directory, or the Node.js code and paste it in index.js in the functions/to_do_list_function directory of your project, and save the file. You can use any IDE of your choice to work with the application's files.
View code for ToDoList.java and index.js
Copied
import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import java.io.InputStreamReader; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import com.catalyst.advanced.CatalystAdvancedIOHandler; import com.zc.component.object.ZCObject; import com.zc.component.object.ZCRowObject; import com.zc.component.object.ZCTable; import com.zc.component.zcql.ZCQL; public class ToDoList implements CatalystAdvancedIOHandler { private static final String GET = "GET"; private static final String POST = "POST"; private static final String DELETE = "DELETE"; private JSONObject responseData = new JSONObject(); private static final Logger LOGGER = Logger.getLogger(ToDoList.class.getName()); @Override public void runner(HttpServletRequest request, HttpServletResponse response) throws Exception { try { String uri = request.getRequestURI(); String method = request.getMethod(); //GET method gets data from the TodoItems table in the Data Store. if (method.equals(GET) && uri.equals("/all")) { Integer page = Integer.parseInt(request.getParameter("page")); Integer perPage = Integer.parseInt(request.getParameter("perPage")) ; Integer totalTodos = Integer .parseInt(ZCQL.getInstance().executeQuery("SELECT COUNT(ROWID) FROM TodoItems").get(0) .get("TodoItems", "ROWID").toString()); Boolean hasMore = totalTodos > page * perPage; ArrayList
> todoItems = new ArrayList >(); ZCQL.getInstance().executeQuery(String.format("SELECT ROWID,Notes FROM TodoItems LIMIT %d,%d", (page - 1) * perPage + 1, perPage)).forEach(row -> { todoItems.add(new HashMap () { { put("id", row.get("TodoItems", "ROWID").toString()); put("notes", row.get("TodoItems", "Notes").toString()); } }); }); response.setStatus(200); responseData.put("status", "success"); responseData.put("data", new JSONObject() { { put("hasMore", hasMore); put("todoItems", todoItems); } }); //POST method sends data to persist in the TodoItems table in the Data Store } else if (method.equals(POST) && uri.equals("/add")) { JSONParser jsonParser = new JSONParser(); ServletInputStream requestBody = request.getInputStream(); JSONObject jsonObject = (JSONObject) jsonParser.parse(new InputStreamReader(requestBody, "UTF-8")); String notes = jsonObject.get("notes").toString(); ZCRowObject row = ZCRowObject.getInstance(); row.set("Notes", notes); ZCRowObject todoItem = ZCObject.getInstance().getTable("TodoItems").insertRow(row); response.setStatus(200); responseData.put("status", "success"); responseData.put("data", new JSONObject() { { put("todoItem", new JSONObject() { { put("id", todoItem.get("ROWID").toString()); put("notes", todoItem.get("Notes").toString()); } }); } }); //Delete method deletes the selected items from the Data Store } else if (method.equals(DELETE)) { ZCTable table = ZCObject.getInstance().getTable("TodoItems"); table.deleteRow(Long.parseLong(uri.substring(1))); response.setStatus(200); responseData.put("status", "success"); responseData.put("data", new JSONObject() { { put("todoItem", new JSONObject() { { put("id", uri.substring(1)); } }); } }); } else { response.setStatus(404); responseData.put("status", "failure"); responseData.put("message", "Please check if the URL trying to access is a correct one"); } } catch (Exception e) { LOGGER.log(Level.SEVERE, "Exception in Main", e); responseData.put("status", "failure"); responseData.put("message", "We're unable to process the request."); } response.setContentType("application/json"); response.getWriter().write(responseData.toString()); } } Copied
const express = require('express'); const catalystSDK = require('zcatalyst-sdk-node'); const app = express(); app.use(express.json()); app.use((req, res, next) => { const catalyst = catalystSDK.initialize(req); res.locals.catalyst = catalyst; next(); }); //GET API. Get existing tasks if any from the server. app.get('/all', async (req, res) => { try { const { catalyst } = res.locals; const page = parseInt(req.query.page); const perPage = parseInt(req.query.perPage); const zcql = catalyst.zcql(); const hasMore = await zcql .executeZCQLQuery(`SELECT COUNT(ROWID) FROM TodoItems`) .then((rows) => parseInt(rows[0].TodoItems.ROWID) > page * perPage); const todoItems = await zcql .executeZCQLQuery( `SELECT ROWID,Notes FROM TodoItems LIMIT ${ (page - 1) * perPage + 1 },${perPage}` ) .then((rows) => rows.map((row) => ({ id: row.TodoItems.ROWID, notes: row.TodoItems.Notes })) ); res.status(200).send({ status: 'success', data: { todoItems, hasMore } }); } catch (err) { console.log(err); res.status(500).send({ status: 'failure', message: "We're unable to process the request." }); } }); // POST API. Contains the logic to create a task app.post('/add', async (req, res) => { try { const { notes } = req.body; const { catalyst } = res.locals; const table = catalyst.datastore().table('TodoItems'); const { ROWID: id } = await table.insertRow({ Notes:notes }); res.status(200).send({ status: 'success', data: { todoItem: { id, notes } } }); } catch (err) { console.log(err); res.status(500).send({ status: 'failure', message: "We're unable to process the request." }); } }); // DELETE API. Contains the logic to delete a task. app.delete('/:ROWID', async (req, res) => { try { const { ROWID } = req.params; const { catalyst } = res.locals; const table = catalyst.datastore().table('TodoItems'); await table.deleteRow(ROWID); res.status(200).send({ status: 'success', data: { todoItem: { id: ROWID } } }); } catch (err) { console.log(err); res.status(500).send({ status: 'failure', message: "We're unable to process the request." }); } }); module.exports = app;
The functions directory is now configured.