Creating a REST API with Node.js and an Oracle Database. Part 3

Part 3. Creating a REST API: handling GET requests



In the previous article, you established a connection to the database.



In the same, add the routing, controller, and database logic to process the HTTP GET request to the “employees” API endpoint.



Adding Routing Logic



Express ships with the Router class, which simplifies the routing of HTTP requests to the appropriate controller logic. Route paths define the endpoints of an API URL and may contain route parameters that capture values ​​in a URL.



There are many ways to determine the routes for your application. For example, when the application starts, you can read all the files in the controller directory and automatically generate routing logic based on some predefined rules, such as the file names and properties that they provide. Alternatively, you can add the file to the configuration directory and read it at startup.



In this application, you will use a slightly lower level approach, programmatically defining routes through the new router module. Create a new file called router.js in the services directory. Add the following code to the file and save the changes.



const express = require('express'); const router = new express.Router(); const employees = require('../controllers/employees.js'); router.route('/employees/:id?') .get(employees.get); module.exports = router;
      
      





The router module starts by requesting the Express module, and then creates a new instance of the Router Express class. The route method of the router module is used to determine the route based on the transmitted data. The path includes an optional (due to a question mark) parameter named id. The route returned from router has methods that match HTTP methods and allow handlers to be defined. In this case, the get method is used to map the incoming GET request to the get function defined in the employee controller (which will be created below).



At the moment you have a router, but it is not used in the application. To use it, open the services / web-server.js file and delete the line at the top, which requires a database module (it was used only for testing in the previous post ). Add the following line of code in its place.



 // *** line that requires ../config/web-server.js is here *** const router = require('./router.js');
      
      





Then use the following code to replace the entire app.get handler, which responds to GET requests using the database module (all 7 lines).



 // *** line that adds morgan to app here *** // Mount the router at /api so all its routes start with /api app.use('/api', router);
      
      





Now the router is requested in the web service module and is "mounted" in / api. This means that the full URL for the employee endpoint will be http: // server: port / api / employee /: id.



Adding Controller Logic



The controller logic will come into operation from the moment the endpoint URL and HTTP method are known. Since the web server is built using Express, the controller logic will be determined using special middleware or functions that have access to request and response objects, as well as to the next function.



The middleware function will use the input from the request object to generate a response that is sent to the response object. The next function is typically used to invoke the next middleware function in the pipeline. However, in this API, the controller logic will be the last step in the pipeline and complete the HTTP response. The next function will only be called if an error occurs that passes control to the standard Express error handler.



Go to the controllers directory and create a new file called employee.js . Copy and paste the following code into the file and save the changes.



 /*01*/const employees = require('../db_apis/employees.js'); /*02*/ /*03*/async function get(req, res, next) { /*04*/ try { /*05*/ const context = {}; /*06*/ /*07*/ context.id = parseInt(req.params.id, 10); /*08*/ /*09*/ const rows = await employees.find(context); /*10*/ /*11*/ if (req.params.id) { /*12*/ if (rows.length === 1) { /*13*/ res.status(200).json(rows[0]); /*14*/ } else { /*15*/ res.status(404).end(); /*16*/ } /*17*/ } else { /*18*/ res.status(200).json(rows); /*19*/ } /*20*/ } catch (err) { /*21*/ next(err); /*22*/ } /*23*/} /*24*/ /*25*/module.exports.get = get;
      
      





Line 1: Employee Database API (to be created below).

Lines 3-23: An asynchronous function named get is declared. The try-catch block is used in the function body to catch exceptions thrown in the main thread and pass them to the next function.

Lines 5-7: a constant with a named context is declared - this is a universal object that will contain properties related to the database API search method. The id property is added to the context based on the value that comes through req.params.id.

Line 9: The find method is used to retrieve the appropriate employees records in the database.

Lines 11-19: Conditional logic is used to determine the correct HTTP status code and response body. If one employee was requested but not found, the error code “404 Not Found” is sent as a response. Otherwise, a 200 OK code is sent along with the JSON-based response body.

Line 25: module export so that you can add to other modules



The req.params object is just one of several properties used to get data from an incoming request object. Other common properties include req.query for query string values ​​in the URL, req.body for the request body, and req.cookies. HTTP headers can be obtained using the req.get method.



Adding Database Logic



To start the employee database module, go to the db_apis directory and create a new file called employee.js . Add the following code to the file.



 const database = require('../services/database.js'); const baseQuery = `select employee_id "id", first_name "first_name", last_name "last_name", email "email", phone_number "phone_number", hire_date "hire_date", job_id "job_id", salary "salary", commission_pct "commission_pct", manager_id "manager_id", department_id "department_id" from employees`; async function find(context) { let query = baseQuery; const binds = {}; if (context.id) { binds.employee_id = context.id; query += `\nwhere employee_id = :employee_id`; } const result = await database.simpleExecute(query, binds); return result.rows; } module.exports.find = find;
      
      





The employee database module introduces the general database module and initializes a constant named baseQuery for the SQL query in the employee table. The double-quoted column aliases are used to control the case of returned keys.



Then a function called find is declared, which is used to execute the query and return the extracted rows. If the passed context parameter is set to true, then the where clause is added to the request, so only one employee is returned.



Note that the context.id value was not added to the request directly. Instead, a placeholder with the name: employee_id was used - this is called a bind variable . Using Oracle database binding variables is very important in terms of security and performance. The value of bind variable is assigned to the binds object, which is passed along with the query to database.simpleExecute. Finally, rows retrieved from the database are returned to the caller.



Launch the application and go to the browser at http: // localhost: 3000 / api / employee. You should see the list of employees as follows (I collapsed a couple):

image

You can select one employee by adding an identifier to the end of the URL, for example: http: // localhost: 3000 / api / employee / 100.



image



At this point, your API can handle GET requests at the endpoint of employees. In the next post, you will extend CRUD functionality by adding logic that processes POST, PUT, and DELETE requests.



All Articles