-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
77e15ac
commit 4283914
Showing
15 changed files
with
600 additions
and
279 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "@frameless/kennisbank-api", | ||
"version": "0.0.0", | ||
"private": true, | ||
"author": "@frameless", | ||
"description": "Kennisbank API for PDC", | ||
"license": "EUPL-1.2", | ||
"keywords": [], | ||
"scripts": { | ||
"prebuild": "yarn clean", | ||
"build": "tsc -p ./tsconfig.json", | ||
"watch": "tsc -p ./tsconfig.json -w", | ||
"start": "node dist/server.js", | ||
"dev": "nodemon src/server.ts", | ||
"clean": "rimraf dist", | ||
"lint-build": "tsc --noEmit --project tsconfig.json" | ||
}, | ||
"dependencies": { | ||
"dotenv": "16.4.5", | ||
"express": "4.21.0" | ||
}, | ||
"devDependencies": { | ||
"nodemon": "3.1.7", | ||
"rimraf": "6.0.1", | ||
"typescript": "5.0.4" | ||
}, | ||
"repository": { | ||
"type": "git+ssh", | ||
"url": "git@github.com:frameless/strapi.git", | ||
"directory": "apps/kennisbank-api" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { kennisartikelController } from './kennisartikel'; |
88 changes: 88 additions & 0 deletions
88
apps/kennisbank-api/src/controllers/kennisartikel/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import type { RequestHandler } from 'express'; | ||
import { SEARCH_PRODUCT } from '../../queries'; | ||
import { fetchData } from '../../utils'; | ||
|
||
export const kennisartikelController: RequestHandler = async (req, res, next) => { | ||
const locale = (req.query?.locale as string) || 'nl'; | ||
const query = req.query?.query as string; | ||
const graphqlURL = new URL('/graphql', process.env.STRAPI_PRIVATE_URL); | ||
try { | ||
const { data } = await fetchData<any>({ | ||
url: graphqlURL.href, | ||
query: SEARCH_PRODUCT, | ||
variables: { locale, query }, | ||
headers: { | ||
Authorization: `Bearer ${process.env.PDC_STRAPI_API_TOKEN}`, | ||
}, | ||
}); | ||
|
||
res.set('Content-Type', 'application/json'); | ||
if (data && data.products && data.products?.data.length > 0) { | ||
const productAttributes = data.products.data[0].attributes; | ||
res.status(200); | ||
res.set('Cache-control', 'public, s-maxage=86400, stale-while-revalidate'); | ||
const upnUri = new URL(`products/${productAttributes.slug}`, process.env.FRONTEND_PUBLIC_URL); | ||
const contentBlock = productAttributes?.sections.find( | ||
({ component }: any) => component === 'ComponentComponentsUtrechtRichText', | ||
); | ||
const metaTags = productAttributes?.metaTags; | ||
const trefwoorden = metaTags?.keymatch?.split(', ').map((trefwoord: string) => ({ trefwoord })) || []; | ||
|
||
const kannisartikel_schema = { | ||
url: productAttributes.slug, | ||
uuid: data.products?.data[0].uuid, | ||
upnUri: upnUri.href, | ||
publicatieDatum: productAttributes.createdAt, | ||
productAanwezig: true, | ||
productValtOnder: null, // we need an extra field for this | ||
// verantwoordelijkeOrganisatie: { | ||
// url: '', | ||
// owmsIdentifier: '', | ||
// owmsPrefLabel: '', | ||
// owmsEndDate: '2023-12-31T23:59:59Z' | ||
// }, | ||
locaties: null, //Een lijst met locaties waarop dit product beschikbaar is. Deze is nog niet nodig voor KISS en mag null zijn. Dit obecjt is dus nog niet opgenomen in dit schema | ||
doelgroep: productAttributes?.catalogiMeta?.audience[0].type, //TODO: We need to verify whether a product in the Strapi dashboard can have multiple values stored as an array. | ||
// afdelingen: [ | ||
// { | ||
// afdelingId: '', | ||
// afdelingnaam: '' | ||
// } | ||
// ], | ||
beschikbareTalen: '', | ||
vertalingen: [ | ||
{ | ||
taal: productAttributes?.locale, | ||
titel: productAttributes?.title, | ||
|
||
contact: contentBlock?.kennisartikelCategorie === 'contact' ? contentBlock.content : undefined, | ||
deskMemo: contentBlock?.kennisartikelCategorie === 'deskMemo' ? contentBlock.content : undefined, | ||
tekst: contentBlock?.kennisartikelCategorie === 'inleiding' ? contentBlock.content : undefined, | ||
procedureBeschrijving: | ||
contentBlock?.kennisartikelCategorie === 'aanvraag' ? contentBlock.content : undefined, | ||
bewijs: contentBlock?.kennisartikelCategorie === 'bewijs' ? contentBlock.content : undefined, | ||
vereisten: contentBlock?.kennisartikelCategorie === 'voorwaarden' ? contentBlock.content : undefined, | ||
bezwaarEnBeroep: contentBlock?.kennisartikelCategorie === 'bezwaar' ? contentBlock.content : undefined, | ||
kostenEnBetaalmethoden: | ||
contentBlock?.kennisartikelCategorie === 'kosten' ? contentBlock.content : undefined, | ||
uitersteTermijn: contentBlock?.kennisartikelCategorie === 'termijn' ? contentBlock.content : undefined, | ||
wtdBijGeenReactie: | ||
contentBlock?.kennisartikelCategorie === 'wat_te_doen_bij_geen_reactie' | ||
? contentBlock.content | ||
: undefined, | ||
notice: contentBlock?.kennisartikelCategorie === 'bijzonderheden' ? contentBlock.content : undefined, | ||
trefwoorden, | ||
datumWijziging: productAttributes.updatedAt, | ||
}, | ||
], | ||
}; | ||
return res.send(kannisartikel_schema); | ||
} | ||
res.status(200); | ||
|
||
return res.send([]); | ||
} catch (error) { | ||
next(error); | ||
return null; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const gql = (query: any) => query; | ||
export const SEARCH_PRODUCT = gql(` | ||
query searchProduct($locale: I18NLocaleCode, $query: String) { | ||
products(locale: $locale, pagination: {start: 0, limit: -1}, filters: { title: {containsi: $query}}) { | ||
data { | ||
id | ||
attributes { | ||
title | ||
slug | ||
locale | ||
updatedAt | ||
createdAt | ||
locale | ||
metaTags { | ||
keymatch | ||
title | ||
description | ||
} | ||
sections { | ||
... on ComponentComponentsUtrechtRichText { | ||
id | ||
content | ||
kennisartikelCategorie | ||
component:__typename | ||
} | ||
} | ||
catalogiMeta { | ||
abstract | ||
spatial { | ||
scheme | ||
resourceIdentifier | ||
} | ||
authority { | ||
scheme | ||
resourceIdentifier | ||
} | ||
audience { | ||
id | ||
type | ||
} | ||
onlineRequest { | ||
type | ||
} | ||
} | ||
pdc_metadata { | ||
uplProductNaam | ||
} | ||
} | ||
} | ||
} | ||
} | ||
`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default as kennisartikel } from './kennisartikel'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import express from 'express'; | ||
import { kennisartikelController } from '../../controllers'; | ||
|
||
const router = express.Router({ mergeParams: true }); | ||
|
||
router.get('/kennisartikel', kennisartikelController); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { config } from 'dotenv'; | ||
import express from 'express'; | ||
import { NextFunction, Request, Response } from 'express'; | ||
import { kennisartikel } from './routers'; | ||
import { envAvailability, ErrorHandler } from './utils'; | ||
|
||
config(); | ||
// Validate environment variables | ||
envAvailability({ | ||
env: process.env, | ||
keys: ['STRAPI_PRIVATE_URL', 'PDC_STRAPI_API_TOKEN', 'FRONTEND_PUBLIC_URL', 'KENNIS_BANK_API_PORT'], | ||
}); | ||
|
||
const app = express(); | ||
|
||
const port = process.env.KENNIS_BANK_API_PORT; | ||
// Centralized error handler middleware | ||
const globalErrorHandler = (err: ErrorHandler, _req: Request, res: Response, _next: NextFunction) => { | ||
if (err instanceof ErrorHandler || (err as ErrorHandler)?.isOperational) { | ||
// Send the proper error response with status code and message | ||
return res.status(err?.options?.statusCode || 500).json({ | ||
message: err.message, | ||
}); | ||
} | ||
|
||
// If it's an unknown error (not an operational error), log it and send a generic response | ||
// eslint-disable-next-line no-console | ||
console.error('Unexpected error:', err); | ||
|
||
return res.status(500).json({ | ||
message: 'An unexpected error occurred.', | ||
}); | ||
}; | ||
// Use global error handler middleware | ||
app.use(globalErrorHandler); | ||
/** | ||
* Routes | ||
* /api/kennisartikel | ||
*/ | ||
app.use('/api', kennisartikel); | ||
// handle non existing routes | ||
app.use((_req, res) => { | ||
res.status(404).send('Route not found'); | ||
}); | ||
app.listen(port, () => { | ||
// eslint-disable-next-line no-console | ||
console.log(`Kennesbank app listening on port ${port}!`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
interface EnvValidator { | ||
env: any; | ||
keys: string[]; | ||
} | ||
export const envAvailability = ({ env, keys }: EnvValidator) => { | ||
keys?.forEach((key: string) => { | ||
if (!env[key]) { | ||
throw new Error(`Missing required environment variable: ${key}`); | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export type Options = { | ||
statusCode: number; | ||
}; | ||
export class ErrorHandler extends Error { | ||
isOperational: boolean; // this flag for custom error identification | ||
|
||
constructor( | ||
message?: string, | ||
public options?: Options, | ||
) { | ||
super(message); | ||
this.name = 'ErrorHandler'; | ||
this.options = options; | ||
this.isOperational = true; // Operational errors should be marked | ||
} | ||
} |
Oops, something went wrong.