@bratislava/ginis-sdk 0.5.0 → 0.6.0

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.
Files changed (4) hide show
  1. package/README.md +102 -67
  2. package/dist/index.d.ts +2096 -230
  3. package/dist/index.js +1055 -119
  4. package/package.json +53 -28
package/README.md CHANGED
@@ -2,19 +2,15 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@bratislava/ginis-sdk)](https://www.npmjs.com/package/@bratislava/ginis-sdk)
4
4
 
5
- A small wrapper for most commonly used requests towards the GINIS system. Made to be used by applications of city of [Bratislava](https://github.com/bratislava)
5
+ A small wrapper for most commonly used requests towards the GINIS system. Made to be used by applications of city of [Bratislava](https://github.com/bratislava).
6
6
 
7
7
  ## Installation
8
8
 
9
- `yarn add @bratislava/ginis-sdk`
10
-
11
- or
12
-
13
9
  `npm i @bratislava/ginis-sdk`
14
10
 
15
11
  ## Using the library
16
12
 
17
- To understand how the structure of `Ginis.xml` and `urls` part of the config relates to the GINIS system, read the [GINIS section](https://bratislava.github.io/GINIS) of our documentation site.
13
+ To understand how the structure of `Ginis` and `urls` part of the config relates to the GINIS system, read the [GINIS section](https://bratislava.github.io/GINIS) of our documentation site.
18
14
 
19
15
  You'll need the GINIS credentials. If interacting with the Bratislava deployment, you also need to be connected through VPN or on internal network.
20
16
 
@@ -28,97 +24,136 @@ const ginis = new Ginis({
28
24
  ssl: 'http://host/your/ssl/endpoint/Ssl.svc',
29
25
  },
30
26
  // credentials
31
- username: process.env.GINIS_USERNAME,
32
- password: process.env.GINIS_PASSWORD,
27
+ username: process.env['GINIS_USERNAME'],
28
+ password: process.env['GINIS_PASSWORD'],
33
29
  // if debug === true prints all the requests and responses into console
34
- // warning - these logs WILL include credentials!
30
+ // WARNING - these logs WILL include credentials!
35
31
  debug: true,
36
32
  })
37
33
  ```
38
34
 
39
- Use the xml-returning requests:
35
+ Use the requests:
40
36
 
41
37
  ```ts
42
38
  // the options object uses same keys as the requests in Ginis docs
43
39
  // i.e. https://robot.gordic.cz/xrg/Default.html?c=OpenMethodDetail&moduleName=UDE&version=390&methodName=seznam-dokumentu&type=request
44
- // will throw an Axios error if the request fails
45
- const data = await ginis.json.ssl.detailDokumentu({
40
+ // will throw a Ginis error if the request fails
41
+ const data = await ginis.ssl.detailDokumentu({
46
42
  'Id-dokumentu': 'MAG0X03RYYSN',
47
43
  })
48
44
  ```
49
45
 
46
+ All requests and responses of this library are via JavaScript objects. However, due to underlying Ginis API using XMLs, the object properties are kept consistent with them. They are using a dash case with only the very first letter being capital written in Czech such as `'Id-dokumentu'`, `'Souvisejici-dokumenty'`, or `'Historie-dokumentu'`.
47
+
48
+ ### Error handling
49
+
50
+ The library should only throw instances of `GinisError` for all expected or predictable erroneous situations. If the underlying cause is `AxiosError`, the whole error will be available inside the `GinisError` object under `axiosError` property.
51
+
52
+ ### Response guarantees
53
+
54
+ All responses from this library are validated using `zod` to check for required parameters. Furthermore, all array properties are guaranteed to be defined and to be array. If there are no elements, the array will be empty and if there is only one elements, it will still be wrapped in an array.
55
+
56
+ All values are only defined as strings and are not validated further; e.g. there is no check if
57
+
58
+ - value matches one of the enum values for enum fields
59
+ - value is numeric or in specified range for number fields
60
+ - value matches the format for date fields
61
+
50
62
  ## Extending the library
51
63
 
52
64
  The `src/api` is structured after the GINIS modules, each subdirectory a single service, each file a single action - for more info on the hierarchy, see our [GINIS docs](https://bratislava.github.io/GINIS).
53
65
 
54
- You can read / reproduce / add new requests in the `/src/api/json/[service-name]/[Action-name].ts` (`/src/api/xml` request considered legacy and have slightly different structure). Read through a couple files and you should be set. To get the typescript typing, either copy the structure from official Gordic docs and update the right-hand side by hand (they are usually strings), or make a manual request and use a tool such as quicktype.io.
66
+ TS docs frequently reference [the official Gordic documentation](https://robot.gordic.cz/xrg/Default.html) (you'll need to create an account to access it). Once you are logged in, you can browse the full docs with request/response formats and all the available endpoints (of which we wrap just a subset).
55
67
 
56
- TS docs frequently reference [the official Gordic documentation](https://robot.gordic.cz/xrg/Default.html) (you'll need to create an account to access it). Once you are logged in, you can browse the full docs with request/reponse formats and all the available endpoints (of which we wrap just a subset).
68
+ You can read / reproduce / add new requests in the `/src/api/[service-name]/[Action-name].ts`. Read through a couple files and you should be set. Since the Ginis API uses SOAP directly or inside a multipart request, there are some challenges when dealing with XMLs.
57
69
 
58
- ## Developing and running tests
70
+ ### XML accommodations
59
71
 
60
- For each new service / request you should add appropriate tests in the `__tests__` subdirectory of the service directory. For xml, place them directly in `src/api/xml/__tests__`, one file per service.
72
+ #### Request type
61
73
 
62
- You need to have GINIS credentials setup in `.env` file - see `.env.example`. If interacting with the Bratislava deployment, you also need to be connected through VPN or on internal network.
74
+ The most important part of this particular Ginis API is that the order of the parameters for each request must be in the same order as defined in request's Gordic documentation. JavaScript objects don't guarantee any property order when iterating over them. For this reason, all properties for all requests are defined in an array, and the request type is dynamically derived from it:
63
75
 
64
- Start the test using
76
+ ```ts
77
+ // https://robot.gordic.cz/xrg/Default.html?c=OpenMethodDetail&moduleName=SSL&version=390&methodName=Detail-dokumentu&type=request
78
+ const detailDokumentuRequestProperties = [
79
+ 'Id-dokumentu',
80
+ 'Vyradit-historii',
81
+ 'Vyradit-obsah-spisu',
82
+ 'Vyradit-prilohy',
83
+ 'Vyradit-souvisejici',
84
+ 'Id-esu',
85
+ 'Vyradit-doruceni',
86
+ 'Id-eu',
87
+ ] as const
88
+
89
+ export type DetailDokumentuRequest = {
90
+ [K in (typeof detailDokumentuRequestProperties)[number] as K]?: string
91
+ }
92
+ ```
65
93
 
66
- `yarn test`
94
+ Currently, all request properties are marked as optional strings regardless of their actual type or if they are required by the endpoint. There is no input validation on the library side and all requests are ultimately accepted or rejected directly by the underlying Ginis API.
67
95
 
68
- ## XML example
96
+ #### Response type
69
97
 
70
- We should have services we need available as JSON endpoints, previous xml requests are kept in as documentation.
98
+ Instead of response type we primarily define a validation `zod` schema. We validate the output of the Ginis API to guarantee, that all the required fields are present and populated. We don't validate values as all simple properties are only utilizing string type - see [response guarantees](#response-guarantees).
71
99
 
72
100
  ```ts
73
- // https://robot.gordic.cz/xrg/Default.html?c=OpenMethodDetail&moduleName=UDE&version=390&methodName=seznam-dokumentu&type=request
74
- export const seznamDokumentu = async (
75
- config: GinisConfig,
76
- url: string | undefined,
77
- bodyObj: seznamDokumentu
78
- ) => {
79
- const axiosConfig: AxiosRequestConfig = {
80
- headers: {
81
- 'Content-Type': 'text/xml; charset=utf-8',
82
- SOAPAction: 'http://www.gordic.cz/svc/xrg-ude/v_1.0.0.0/Seznam-dokumentu',
83
- },
84
- }
85
- const body = `
86
- <s:Envelope
87
- xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
88
- xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
89
- <s:Header>
90
- <o:Security s:mustUnderstand="1"
91
- xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
92
- <o:UsernameToken u:Id="uuid-ea5d8d3d-df90-4b69-b034-9026f34a3f21-1">
93
- <o:Username>${config.username}</o:Username>
94
- <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">${
95
- config.password
96
- }</o:Password>
97
- </o:UsernameToken>
98
- </o:Security>
99
- </s:Header>
100
- <s:Body>
101
- <Seznam-dokumentu
102
- xmlns="http://www.gordic.cz/svc/xrg-ude/v_1.0.0.0">
103
- <requestXml>
104
- <Xrg
105
- xmlns="http://www.gordic.cz/xrg/ude/seznam-dokumentu/request/v_1.0.0.0">
106
- <Seznam-dokumentu>
107
- ${Object.entries(bodyObj).map(([key, value]) => `<${key}>${value}</${key}>`)}
108
- </Seznam-dokumentu>
109
- </Xrg>
110
- </requestXml>
111
- </Seznam-dokumentu>
112
- </s:Body>
113
- </s:Envelope>
114
- `
115
- return makeAxiosRequest(axiosConfig, url, body, config.debug)
116
- }
101
+ const detailElPodaniSchema = z.object({
102
+ 'Datum-prijeti': z.string(),
103
+ 'Stav-zpracovani': z.string(),
104
+ 'Duvod-odmitnuti': z.string().optional(),
105
+ 'Stav-podani-kod': z.string(),
106
+ 'Stav-podani-text': z.string().optional(),
107
+ 'Stav-odpovedi-kod': z.string(),
108
+ 'Stav-odpovedi-text': z.string().optional(),
109
+ 'Id-dokumentu': z.string().optional(),
110
+ Vec: z.string().optional(),
111
+ 'Spis-znacka': z.string().optional(),
112
+ Znacka: z.string().optional(),
113
+ })
114
+
115
+ const navazanyDokumentSchema = z.object({
116
+ 'Id-dokumentu': z.string(),
117
+ Vec: z.string().optional(),
118
+ 'Spis-znacka': z.string().optional(),
119
+ Znacka: z.string().optional(),
120
+ })
117
121
  ```
118
122
 
119
- ## Documentation
123
+ Also, we transform all the array fields to actually contain array - empty, with one element, or multiple elements - regardless if the response contains the property or not via the `coercedArray` helper.
124
+
125
+ ```ts
126
+ const detailElPodaniResponseSchema = z.object({
127
+ 'Detail-el-podani': detailElPodaniSchema,
128
+ 'Navazany-dokument': coercedArray(navazanyDokumentSchema),
129
+ })
130
+ ```
131
+
132
+ Then, the response type is derived from the schema as such:
133
+
134
+ ```ts
135
+ export type DetailElPodaniResponse = z.infer<typeof detailElPodaniResponseSchema>
136
+ ```
137
+
138
+ ## Developing and running tests
139
+
140
+ For each new service / request you should add appropriate tests in the `__tests__` subdirectory of the service directory, one file per request.
141
+
142
+ You need to have GINIS credentials setup in `.env` file - see `.env.example`. If interacting with the Bratislava deployment, you also need to be connected through VPN or on internal network.
143
+
144
+ Start the test using
145
+
146
+ ```bash
147
+ npm run test
148
+ ```
149
+
150
+ If you are experiencing circular structure errors related to `req` and/or `rsp` in jest while testing locally, instead use
151
+
152
+ ```bash
153
+ npm run test:detect
154
+ ```
120
155
 
121
- Explore the [docs](https://bratislava.github.io/json-schema-xsd-tools/).
156
+ which detects open handles preventing this issue.
122
157
 
123
158
  ## License
124
159