Call a web API in a Node.js web application
Applies to: Workforce tenants
External tenants (learn more)
In this article, you learn how to call a web API from your Node.js client web app using the access token you acquire in Acquire access token. The web API is protected by Microsoft Entra External ID. This article is the fourth and last part of a four-part guide series.
Prerequisite
- Complete the steps in the first part of this guide series, Prepare external tenant to call an API in a Node.js web application.
- Complete the steps in the second part of this guide series, Prepare app to call an API in a Node.js web application.
- Complete the steps in third the part of this guide series Acquire an access token in your Node.js web app article.
Update code
In your code editor, open routes/todos.js file, then add the following code:
const express = require('express'); const router = express.Router(); const toDoListController = require('../controller/todolistController'); const authProvider = require('../auth/AuthProvider'); const { protectedResources } = require('../authConfig'); // custom middleware to check auth state function isAuthenticated(req, res, next) { if (!req.session.isAuthenticated) { return res.redirect('/auth/signin'); // redirect to sign-in route } next(); } // isAuthenticated checks if user is authenticated router.get('/',isAuthenticated, authProvider.getToken(protectedResources.toDoListAPI.scopes.read),toDoListController.getToDos); router.delete('/', isAuthenticated,authProvider.getToken(protectedResources.toDoListAPI.scopes.write),toDoListController.deleteToDo); router.post('/',isAuthenticated,authProvider.getToken(protectedResources.toDoListAPI.scopes.write),toDoListController.postToDo); module.exports = router;
This file contains express routes for create, read and delete resource in the protected API. Each route uses three middleware functions, which execute in that sequence:
isAuthenticated
checks whether the user is authenticated.getToken
requests an access token. You defined this function earlier in Acquire access token. For example, the create resource route (POST request) requests an access token with read and write permissions.Finally, the
postToDo
ordeleteToDo
getToDos
methods handles the actual logic for manipulating the resource. These functions are defined in controller/todolistController.js file.
In your code editor, open controller/todolistController.js file, then add the following code:
const { callEndpointWithToken } = require('../fetch'); const { protectedResources } = require('../authConfig'); exports.getToDos = async (req, res, next) => { try { const todoResponse = await callEndpointWithToken( protectedResources.toDoListAPI.endpoint, req.session.accessToken, 'GET' ); res.render('todos', { isAuthenticated: req.session.isAuthenticated, todos: todoResponse.data }); } catch (error) { next(error); } }; exports.postToDo = async (req, res, next) => { try { if (!!req.body.description) { let todoItem = { description: req.body.description, }; await callEndpointWithToken( protectedResources.toDoListAPI.endpoint, req.session.accessToken, 'POST', todoItem ); res.redirect('todos'); } else { throw { error: 'empty request' }; } } catch (error) { next(error); } }; exports.deleteToDo = async (req, res, next) => { try { await callEndpointWithToken( protectedResources.toDoListAPI.endpoint, req.session.accessToken, 'DELETE', req.body._id ); res.redirect('todos'); } catch (error) { next(error); } };
Each of these functions collects all the information required to call an API. It then delegates the work to the
callEndpointWithToken
function and waits for a response. ThecallEndpointWithToken
function is defined in the fetch.js file. For example, to create a resource in the API, thepostToDo
function passes an endpoint, an access token, an HTTP method and a request body to thecallEndpointWithToken
function and waits for a response. It then redirects the user to the todo.hbs view to show all tasks.In your code editor, open fetch.js file, then add the following code:
const axios = require('axios'); /** * Makes an Authorization "Bearer" request with the given accessToken to the given endpoint. * @param endpoint * @param accessToken * @param method */ const callEndpointWithToken = async (endpoint, accessToken, method, data = null) => { const options = { headers: { Authorization: `Bearer ${accessToken}`, }, }; switch (method) { case 'GET': return await axios.get(endpoint, options); case 'POST': return await axios.post(endpoint, data, options); case 'DELETE': return await axios.delete(endpoint + `/${data}`, options); default: return null; } }; module.exports = { callEndpointWithToken, };
This function makes the actual API call. Notice how you include the access token as the value of bearer token in the HTTP request header:
//... headers: { Authorization: `Bearer ${accessToken}`, } //...
In your code editor, open .env file, then add the following configuration:
# Use this variable only in the development environment. # Please remove the variable when you move the app to the production environment. NODE_TLS_REJECT_UNAUTHORIZED='0'
The
NODE_TLS_REJECT_UNAUTHORIZED='0'
setting in your .env file instructs Node.js to ignore any SSL certificate errors, such as the self-signed certificate error.In your code editor, open the
app.js
file, then:Add the todo router by using the following code:
var todosRouter = require('./routes/todos');
Use the todo router by using the following code:
app.use('/todos', todosRouter);
Run and test web app and API
At this point, you're ready to call the web API from the client web app:
Use the steps in Secure an ASP.NET web API article to start your web API app. Your web API is now ready to serve client requests.
In your terminal, make sure you're in the project folder that contains your client web app such as
ciam-sign-in-call-api-node-express-web-app
, then run the following command:npm start
Your client web app starts.
Use the steps in Run and test sample web app and API to demonstrate how the client app calls the web API.
Related content
You may want to: