Skip to content

Commit 462808c

Browse files
committed
Display errors from the API in the UI
Closes #218
1 parent 704acab commit 462808c

File tree

2 files changed

+58
-13
lines changed

2 files changed

+58
-13
lines changed

Sample-01/api-server.js

+33-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ const express = require("express");
22
const cors = require("cors");
33
const morgan = require("morgan");
44
const helmet = require("helmet");
5-
const { auth } = require("express-oauth2-jwt-bearer");
5+
const {
6+
auth,
7+
InvalidTokenError,
8+
InvalidRequestError,
9+
InsufficientScopeError,
10+
requiredScopes,
11+
} = require("express-oauth2-jwt-bearer");
612
const authConfig = require("./src/auth_config.json");
713

814
const app = express();
@@ -11,11 +17,7 @@ const port = process.env.API_PORT || 3001;
1117
const appPort = process.env.SERVER_PORT || 3000;
1218
const appOrigin = authConfig.appOrigin || `http://localhost:${appPort}`;
1319

14-
if (
15-
!authConfig.domain ||
16-
!authConfig.audience ||
17-
authConfig.audience === "YOUR_API_IDENTIFIER"
18-
) {
20+
if (!authConfig.domain || !authConfig.audience || authConfig.audience === "YOUR_API_IDENTIFIER") {
1921
console.log(
2022
"Exiting: Please make sure that auth_config.json is in place and populated with valid domain and audience values"
2123
);
@@ -27,16 +29,35 @@ app.use(morgan("dev"));
2729
app.use(helmet());
2830
app.use(cors({ origin: appOrigin }));
2931

30-
const checkJwt = auth({
31-
audience: authConfig.audience,
32-
issuerBaseURL: `https://${authConfig.domain}/`,
33-
algorithms: ["RS256"],
34-
});
32+
app.use(
33+
auth({
34+
audience: authConfig.audience,
35+
issuerBaseURL: `https://${authConfig.domain}/`,
36+
algorithms: ["RS256"],
37+
})
38+
);
3539

36-
app.get("/api/external", checkJwt, (req, res) => {
40+
app.get("/api/external", requiredScopes('admin'), (req, res) => {
3741
res.send({
3842
msg: "Your access token was successfully validated!",
3943
});
4044
});
4145

46+
// Custom error handler that will turn the errors from express-oauth2-jwt-bearer into a JSON object
47+
// for the UI to handle
48+
app.use((err, req, res, next) => {
49+
if (
50+
err instanceof InvalidTokenError ||
51+
err instanceof InvalidRequestError ||
52+
err instanceof InsufficientScopeError
53+
) {
54+
return res.status(err.status).send({
55+
error: err.code,
56+
message: err.message,
57+
});
58+
}
59+
60+
res.send(err);
61+
});
62+
4263
app.listen(port, () => console.log(`API Server listening on port ${port}`));

Sample-01/src/views/ExternalApi.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ export const ExternalApiComponent = () => {
1010

1111
const [state, setState] = useState({
1212
showResult: false,
13-
apiMessage: "",
13+
showApiError: false,
1414
error: null,
15+
apiMessage: "",
16+
apiError: null,
1517
});
1618

1719
const {
@@ -64,12 +66,27 @@ export const ExternalApiComponent = () => {
6466
},
6567
});
6668

69+
if (!response.ok) {
70+
const apiError = response.headers.get('content-type')?.includes('application/json')
71+
? JSON.stringify(await response.json(), null, 2)
72+
: await response.text();
73+
setState({
74+
...state,
75+
showApiError: true,
76+
showResult: false,
77+
apiError
78+
});
79+
return;
80+
}
81+
6782
const responseData = await response.json();
6883

6984
setState({
7085
...state,
7186
showResult: true,
7287
apiMessage: responseData,
88+
apiError: null,
89+
showApiError: false
7390
});
7491
} catch (error) {
7592
setState({
@@ -188,6 +205,13 @@ export const ExternalApiComponent = () => {
188205
<Highlight text={JSON.stringify(state.apiMessage, null, 2)} />
189206
</div>
190207
)}
208+
209+
{state.showApiError && (
210+
<div className="result-block" data-testid="api-result">
211+
<h6 className="muted">Error</h6>
212+
<Highlight text={state.apiError} />
213+
</div>
214+
)}
191215
</div>
192216
</>
193217
);

0 commit comments

Comments
 (0)