Skip to content

Commit

Permalink
Display errors from the API in the UI
Browse files Browse the repository at this point in the history
Closes #218
  • Loading branch information
ewanharris committed Mar 29, 2023
1 parent abb0223 commit fcf75e7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 13 deletions.
45 changes: 33 additions & 12 deletions Sample-01/api-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const helmet = require("helmet");
const { auth } = require("express-oauth2-jwt-bearer");
const {
auth,
InvalidTokenError,
InvalidRequestError,
InsufficientScopeError,
requiredScopes,
} = require("express-oauth2-jwt-bearer");
const authConfig = require("./src/auth_config.json");

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

if (
!authConfig.domain ||
!authConfig.audience ||
authConfig.audience === "YOUR_API_IDENTIFIER"
) {
if (!authConfig.domain || !authConfig.audience || authConfig.audience === "YOUR_API_IDENTIFIER") {
console.log(
"Exiting: Please make sure that auth_config.json is in place and populated with valid domain and audience values"
);
Expand All @@ -27,16 +29,35 @@ app.use(morgan("dev"));
app.use(helmet());
app.use(cors({ origin: appOrigin }));

const checkJwt = auth({
audience: authConfig.audience,
issuerBaseURL: `https://${authConfig.domain}/`,
algorithms: ["RS256"],
});
app.use(
auth({
audience: authConfig.audience,
issuerBaseURL: `https://${authConfig.domain}/`,
algorithms: ["RS256"],
})
);

app.get("/api/external", checkJwt, (req, res) => {
app.get("/api/external", requiredScopes('admin'), (req, res) => {
res.send({
msg: "Your access token was successfully validated!",
});
});

// Custom error handler that will turn the errors from express-oauth2-jwt-bearer into a JSON object
// for the UI to handle
app.use((err, req, res, next) => {
if (
err instanceof InvalidTokenError ||
err instanceof InvalidRequestError ||
err instanceof InsufficientScopeError
) {
return res.status(err.status).send({
error: err.code,
message: err.message,
});
}

res.send(err);
});

app.listen(port, () => console.log(`API Server listening on port ${port}`));
26 changes: 25 additions & 1 deletion Sample-01/src/views/ExternalApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ export const ExternalApiComponent = () => {

const [state, setState] = useState({
showResult: false,
apiMessage: "",
showApiError: false,
error: null,
apiMessage: "",
apiError: null,
});

const {
Expand Down Expand Up @@ -64,12 +66,27 @@ export const ExternalApiComponent = () => {
},
});

if (!response.ok) {
const apiError = response.headers.get('content-type')?.includes('application/json')
? JSON.stringify(await response.json(), null, 2)
: await response.text();
setState({
...state,
showApiError: true,
showResult: false,
apiError
});
return;
}

const responseData = await response.json();

setState({
...state,
showResult: true,
apiMessage: responseData,
apiError: null,
showApiError: false
});
} catch (error) {
setState({
Expand Down Expand Up @@ -188,6 +205,13 @@ export const ExternalApiComponent = () => {
<Highlight text={JSON.stringify(state.apiMessage, null, 2)} />
</div>
)}

{state.showApiError && (
<div className="result-block" data-testid="api-result">
<h6 className="muted">Error</h6>
<Highlight text={state.apiError} />
</div>
)}
</div>
</>
);
Expand Down

0 comments on commit fcf75e7

Please sign in to comment.