@biblioteksentralen/bmdb-search 0.0.0-beta.7 → 0.0.0-beta.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
1
  # @biblioteksentralen/bmdb-search
2
2
 
3
- TODO
3
+ ## 0.0.0-beta.16
4
+
5
+ - [BREAKING] `/{profile}` prefix for all routes
6
+ - Removed `clientIdentifier`
7
+
8
+ ## 0.0.0-beta.14
9
+
10
+ - Refactored `Work.subjects` model
package/README.md CHANGED
@@ -2,78 +2,147 @@
2
2
 
3
3
  TypeScript client for searching Bibliotekenes metadatabrønn (BMDB) using [openapi-fetch](https://openapi-ts.dev/openapi-fetch/).
4
4
 
5
- ## Options
5
+ ## Setup
6
6
 
7
- ### Client identification policy
7
+ ### Setup for server-side usage
8
8
 
9
- The API does not require authentication, but clients should identify themselves using a descriptive
10
- name and a contact address in the `clientIdentifier` string. We will only contact you about usage of the API.
11
-
12
- ## Usage examples
13
-
14
- ### Search works
9
+ If the client is running in an environment that can keep secrets, i.e. server-side, the bundled
10
+ `clientCredentialsAccessTokenGetter` helper can be used to exchange your long-lived OAuth 2.0
11
+ client credentials for short-lived access tokens:
15
12
 
16
13
  ```typescript
17
- import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search";
14
+ import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search/v1";
15
+ import { clientCredentialsAccessTokenGetter } from "@biblioteksentralen/bmdb-search/server";
18
16
 
19
17
  const bmdbSearchClient = createBmdbFetchClient({
20
- clientIdentifier: "client-unique-description",
21
- host: "https://search.data.bs.no",
18
+ host: "https://search.bmdb.no",
19
+ auth: clientCredentialsAccessTokenGetter({
20
+ clientId: process.env.BMDB_CORDATA_API_CLIENT_ID,
21
+ clientSecret: process.env.BMDB_CORDATA_API_CLIENT_SECRET,
22
+ }),
22
23
  });
23
- const { data, error } = await bmdbSearchClient.GET("/works/search", { params: { query: { query: "test" } } });
24
24
  ```
25
25
 
26
- The arguments and response are fully typed.
26
+ Note: If you are planning to access pre-production environments, see notes below on how to
27
+ connect to those below.
27
28
 
28
- ### Usage with tanstack-query, openapi-react-query and next.js
29
+ ### Setup for client-side (frontend) usage
29
30
 
30
- Using [tanstack](https://tanstack.com/query/latest) for fetching with state management and [openapi-react-query](https://openapi-ts.dev/openapi-react-query/) for typing.
31
+ To use the BMDB search client in a client-side environment, i.e. one that cannot keep secrets,
32
+ the client needs to fetch access tokens from a server-side route that you manage.
31
33
 
32
- Add a rewrite in the next.js config file to be able to use the frontend host without violating the content service policy:
34
+ Example:
33
35
 
34
36
  ```typescript
35
- // next.config.js or similar
36
- const searchApiHost = "https://search.data.bs.no";
37
-
38
- const config = {
39
- // ... other config ...
40
- rewrites() {
41
- return [
42
- {
43
- source: "/bmdb/api/:path*",
44
- destination: `${searchApiHost}/bmdb/api/:path*`,
45
- },
46
- ];
37
+ // clients/bmdbClient.ts
38
+ import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search/v1";
39
+
40
+ export const bmdbBrowserClient = createBmdbFetchClient({
41
+ host: "https://search.bmdb.no",
42
+ auth: async () => {
43
+ // Fetches access token from an endpoint you manage
44
+ const response = await fetch("/api/bmdb/access-token");
45
+
46
+ if (!response.ok) {
47
+ throw new Error("Failed to fetch BMDB access token");
48
+ }
49
+
50
+ const { accessToken } = await response.json();
51
+ return accessToken;
47
52
  },
48
- };
53
+ });
54
+ ```
55
+
56
+ Note that the client's auth middleware caches tokens in memory, only calling the endpoint when a new
57
+ token is needed. For this reason, it's recommended to not create a new client for each request, but
58
+ reuse it.
59
+
60
+ The implementation of the server-side API route depends on the programming language and framework
61
+ you use. Below is a simple example for Next.js with App Router:
62
+
63
+ ```typescript
64
+ // app/api/bmdb/access-token/route.ts
65
+ import { clientCredentialsAccessTokenGetter } from "@biblioteksentralen/bmdb-search/server";
66
+
67
+ const getAccessToken = clientCredentialsAccessTokenGetter({
68
+ clientId: process.env.BMDB_CORDATA_API_CLIENT_ID,
69
+ clientSecret: process.env.BMDB_CORDATA_API_CLIENT_SECRET,
70
+ });
71
+
72
+ export async function GET() {
73
+ try {
74
+ // Ask yourself if you want to restrict clients before returning a token
75
+ const accessToken = await getAccessToken();
76
+ return Response.json({ accessToken });
77
+ } catch (err) {
78
+ console.error(`Failed to fetch access token`, err);
79
+ return Response.json({ error: "Failed to fetch access token" }, { status: 500 });
80
+ }
81
+ }
82
+ ```
83
+
84
+ ### Connecting to pre-production environments (dev/test/staging)
85
+
86
+ When connecting to pre-production environments, the OAuth 2.0 Authorization Server Token URL must be
87
+ be specified manually through the `tokenUrl` parameter, and the audience must be specified through the
88
+ `audience` parameter. Example for connecting to the test/staging environment:
89
+
90
+ ```typescript
91
+ const bmdbSearchClient = createBmdbFetchClient({
92
+ host: "https://search-staging.bmdb.no",
93
+ auth: clientCredentialsAccessTokenGetter({
94
+ clientId: process.env.BMDB_CORDATA_API_CLIENT_ID,
95
+ clientSecret: process.env.BMDB_CORDATA_API_CLIENT_SECRET,
96
+ tokenUrl: "https://biblioteksentralen-uat.eu.kinde.com/oauth2/token",
97
+ audience: " https://search-staging.bmdb.no/cordata/",
98
+ }),
99
+ });
49
100
  ```
50
101
 
51
- If necessary, skip in middleware to exempt the API paths from internationalization etc:
102
+ ## Usage
103
+
104
+ ### Search works
52
105
 
53
106
  ```typescript
54
- // middleware.ts
55
- export const config = {
56
- matcher: [
57
- // ...other
58
- "/((?!|bmdb/api|_next/static).*)",
59
- ],
60
- };
107
+ const { data, error } = await bmdbSearchClient.GET("/{searchProfile}/works/search", {
108
+ params: {
109
+ path: { searchProfile: "global" },
110
+ query: { query: "test" },
111
+ },
112
+ });
61
113
  ```
62
114
 
63
- Create hooks and fetch data:
115
+ ### Get works
64
116
 
65
117
  ```typescript
66
- import { createBmdbFetchClient } from "@biblioteksentralen/bmdb-search";
67
- import createReactQueryClient from "openapi-react-query";
118
+ const { data, error } = await bmdbSearchClient.GET("/{searchProfile}/works", {
119
+ params: {
120
+ path: { searchProfile: "deichman" },
121
+ query: { ids: "1237715,1237713" },
122
+ },
123
+ });
124
+ ```
68
125
 
69
- const bmdbSearchClient = createBmdbFetchClient({ clientIdentifier: "client-unique-description" });
70
- const { useQuery } = createReactQueryClient(bmdbSearchClient);
126
+ ### Search agents
71
127
 
72
- const Component = () => {
73
- const { data, error, isLoading } = useQuery("get", "/works/search", { params: { query: { query: "test" } } });
74
- if (isLoading) return <div>Loading</div>;
75
- if (error) return <div>Something went wrong</div>;
76
- return <div>Found {data?.total} works</div>;
77
- };
128
+ ```typescript
129
+ const { data, error } = await bmdbSearchClient.GET("/{searchProfile}/agents/search", {
130
+ params: {
131
+ path: { searchProfile: "tonsberg" },
132
+ query: { query: "test" },
133
+ },
134
+ });
135
+ ```
136
+
137
+ ### Find all contributor roles for a given agent
78
138
 
139
+ ```typescript
140
+ const { data, error } = await bmdbSearchClient.GET("/{searchProfile}/agents/search", {
141
+ params: {
142
+ path: { searchProfile: "global" },
143
+ query: { facet: ["role"], size: 0, facet_terms_size: 20 },
144
+ },
145
+ });
79
146
  ```
147
+
148
+ The arguments and response are fully typed.