orator-serviceserver-restify 2.0.4 → 2.0.7
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/CONTRIBUTING.md +50 -0
- package/README.md +117 -2
- package/docs/.nojekyll +0 -0
- package/docs/README.md +74 -0
- package/docs/_sidebar.md +10 -0
- package/docs/body-parsing.md +57 -0
- package/docs/configuration.md +61 -0
- package/docs/cover.md +11 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/getting-started.md +106 -0
- package/docs/index.html +39 -0
- package/docs/middleware.md +79 -0
- package/docs/retold-catalog.json +41 -0
- package/docs/retold-keyword-index.json +19 -0
- package/package.json +5 -5
- package/source/Orator-ServiceServer-Restify.js +11 -0
- package/test/Orator-ServiceServer-Restify_tests.js +1448 -0
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Contributing to Retold
|
|
2
|
+
|
|
3
|
+
We welcome contributions to Retold and its modules. This guide covers the expectations and process for contributing.
|
|
4
|
+
|
|
5
|
+
## Code of Conduct
|
|
6
|
+
|
|
7
|
+
The Retold community values **empathy**, **equity**, **kindness**, and **thoughtfulness**. We expect all participants to treat each other with respect, assume good intent, and engage constructively. These values apply to all interactions: pull requests, issues, discussions, and code review.
|
|
8
|
+
|
|
9
|
+
## How to Contribute
|
|
10
|
+
|
|
11
|
+
### Pull Requests
|
|
12
|
+
|
|
13
|
+
Pull requests are the preferred method for contributing changes. To submit one:
|
|
14
|
+
|
|
15
|
+
1. Fork the module repository you want to change
|
|
16
|
+
2. Create a branch for your work
|
|
17
|
+
3. Make your changes, following the code style of the module you are editing
|
|
18
|
+
4. Ensure your changes have test coverage (see below)
|
|
19
|
+
5. Open a pull request against the module's main branch
|
|
20
|
+
|
|
21
|
+
**Submitting a pull request does not guarantee it will be accepted.** Maintainers review contributions for fit, quality, and alignment with the project's direction. A PR may be declined, or you may be asked to revise it. This is normal and not a reflection on the quality of your effort.
|
|
22
|
+
|
|
23
|
+
### Reporting Issues
|
|
24
|
+
|
|
25
|
+
If you find a bug or have a feature suggestion, open an issue on the relevant module's repository. Include enough detail to reproduce the problem or understand the proposal.
|
|
26
|
+
|
|
27
|
+
## Test Coverage
|
|
28
|
+
|
|
29
|
+
Every commit must include test coverage for the changes it introduces. Retold modules use Mocha in TDD style. Before submitting:
|
|
30
|
+
|
|
31
|
+
- **Write tests** for any new functionality or bug fixes
|
|
32
|
+
- **Run the existing test suite** with `npm test` and confirm all tests pass
|
|
33
|
+
- **Check coverage** with `npm run coverage` if the module supports it
|
|
34
|
+
|
|
35
|
+
Pull requests that break existing tests or lack coverage for new code will not be merged.
|
|
36
|
+
|
|
37
|
+
## Code Style
|
|
38
|
+
|
|
39
|
+
Follow the conventions of the module you are working in. The general Retold style is:
|
|
40
|
+
|
|
41
|
+
- **Tabs** for indentation, never spaces
|
|
42
|
+
- **Plain JavaScript** only (no TypeScript)
|
|
43
|
+
- **Allman-style braces** (opening brace on its own line)
|
|
44
|
+
- **Variable naming:** `pVariable` for parameters, `tmpVariable` for temporaries, `libSomething` for imports
|
|
45
|
+
|
|
46
|
+
When in doubt, match what the surrounding code does.
|
|
47
|
+
|
|
48
|
+
## Repository Structure
|
|
49
|
+
|
|
50
|
+
Each module is its own git repository. The [retold](https://github.com/stevenvelozo/retold) repository tracks module organization but does not contain module source code. Direct your pull request to the specific module repository where your change belongs.
|
package/README.md
CHANGED
|
@@ -1,3 +1,118 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Orator ServiceServer Restify
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Production HTTP service server for Orator, powered by Restify
|
|
4
|
+
|
|
5
|
+
This is the Restify implementation of the Orator service server interface. It wraps [Restify](https://restify.com/) to provide a full-featured HTTP API server with body parsing, middleware, and all standard HTTP verbs. When you need a real network-facing API server, this is the module you reach for.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Full HTTP Support** - All standard HTTP verbs (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
|
|
10
|
+
- **Restify Middleware** - Both `use` (post-routing) and `pre` (pre-routing) middleware support
|
|
11
|
+
- **Body Parsing** - Built-in Restify body parser with multipart support
|
|
12
|
+
- **Configurable** - Restify server options passed through from Fable settings
|
|
13
|
+
- **Fable Service Provider** - Registers as `OratorServiceServer` in the Fable service manager
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
const libFable = require('fable');
|
|
19
|
+
const libOrator = require('orator');
|
|
20
|
+
const libOratorServiceServerRestify = require('orator-serviceserver-restify');
|
|
21
|
+
|
|
22
|
+
const _Fable = new libFable({
|
|
23
|
+
Product: 'MyAPIServer',
|
|
24
|
+
ProductVersion: '1.0.0',
|
|
25
|
+
ServicePort: 8080
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
_Fable.serviceManager.addServiceType('Orator', libOrator);
|
|
29
|
+
_Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
|
|
30
|
+
_Fable.serviceManager.instantiateServiceProvider('Orator');
|
|
31
|
+
_Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
|
|
32
|
+
|
|
33
|
+
// Register routes
|
|
34
|
+
_Fable.Orator.serviceServer.get('/api/status',
|
|
35
|
+
(pRequest, pResponse, fNext) =>
|
|
36
|
+
{
|
|
37
|
+
pResponse.send({ status: 'ok' });
|
|
38
|
+
return fNext();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
_Fable.Orator.serviceServer.postWithBodyParser('/api/items',
|
|
42
|
+
(pRequest, pResponse, fNext) =>
|
|
43
|
+
{
|
|
44
|
+
pResponse.send({ created: true, item: pRequest.body });
|
|
45
|
+
return fNext();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Start the server
|
|
49
|
+
_Fable.Orator.startService();
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install orator-serviceserver-restify
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
Restify-specific configuration is passed through the `RestifyConfiguration` setting:
|
|
61
|
+
|
|
62
|
+
```javascript
|
|
63
|
+
const _Fable = new libFable({
|
|
64
|
+
ServicePort: 8080,
|
|
65
|
+
RestifyConfiguration: {
|
|
66
|
+
strictNext: true
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Setting | Type | Default | Description |
|
|
72
|
+
|---------|------|---------|-------------|
|
|
73
|
+
| `RestifyConfiguration` | object | `{}` | Options passed to `restify.createServer()` |
|
|
74
|
+
| `RestifyConfiguration.maxParamLength` | number | `Number.MAX_SAFE_INTEGER` | Maximum URL parameter length |
|
|
75
|
+
|
|
76
|
+
## Middleware
|
|
77
|
+
|
|
78
|
+
The Restify server supports two types of middleware:
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const tmpServiceServer = _Fable.Orator.serviceServer;
|
|
82
|
+
|
|
83
|
+
// Post-routing middleware (runs after route matching)
|
|
84
|
+
tmpServiceServer.use(
|
|
85
|
+
(pRequest, pResponse, fNext) =>
|
|
86
|
+
{
|
|
87
|
+
return fNext();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Pre-routing middleware (runs before route matching)
|
|
91
|
+
tmpServiceServer.pre(
|
|
92
|
+
(pRequest, pResponse, fNext) =>
|
|
93
|
+
{
|
|
94
|
+
return fNext();
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
Full documentation is available in the [`docs`](./docs) folder, or served locally:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx docsify-cli serve docs
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Related Packages
|
|
107
|
+
|
|
108
|
+
- [orator](https://github.com/stevenvelozo/orator) - API server abstraction
|
|
109
|
+
- [orator-serviceserver-base](https://github.com/stevenvelozo/orator-serviceserver-base) - Abstract service server base class
|
|
110
|
+
- [fable](https://github.com/stevenvelozo/fable) - Application services framework
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
|
115
|
+
|
|
116
|
+
## Contributing
|
|
117
|
+
|
|
118
|
+
Pull requests are welcome. For details on our code of conduct, contribution process, and testing requirements, see the [Retold Contributing Guide](https://github.com/stevenvelozo/retold/blob/main/docs/contributing.md).
|
package/docs/.nojekyll
ADDED
|
File without changes
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Orator ServiceServer Restify
|
|
2
|
+
|
|
3
|
+
> Production HTTP service server for Orator, powered by Restify
|
|
4
|
+
|
|
5
|
+
This is the Restify implementation of the Orator service server interface. It wraps [Restify](https://restify.com/) to provide a production-ready HTTP API server. The module extends `orator-serviceserver-base`, overriding the `do*` methods to delegate route registration directly to the underlying Restify server instance.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Full HTTP Support** - All standard HTTP verbs (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)
|
|
10
|
+
- **Restify Middleware** - Both `use` (post-routing) and `pre` (pre-routing) middleware support
|
|
11
|
+
- **Body Parsing** - Built-in Restify body parser with multipart support
|
|
12
|
+
- **Configurable** - Restify server options passed through from Fable settings
|
|
13
|
+
- **Fable Service Provider** - Registers as `OratorServiceServer` in the Fable service manager
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
const libFable = require('fable');
|
|
19
|
+
const libOrator = require('orator');
|
|
20
|
+
const libOratorServiceServerRestify = require('orator-serviceserver-restify');
|
|
21
|
+
|
|
22
|
+
const _Fable = new libFable({
|
|
23
|
+
Product: 'MyAPIServer',
|
|
24
|
+
ProductVersion: '1.0.0',
|
|
25
|
+
ServicePort: 8080
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
_Fable.serviceManager.addServiceType('Orator', libOrator);
|
|
29
|
+
_Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
|
|
30
|
+
_Fable.serviceManager.instantiateServiceProvider('Orator');
|
|
31
|
+
_Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
|
|
32
|
+
|
|
33
|
+
_Fable.Orator.serviceServer.get('/api/hello',
|
|
34
|
+
(pRequest, pResponse, fNext) =>
|
|
35
|
+
{
|
|
36
|
+
pResponse.send({ message: 'Hello from Restify!' });
|
|
37
|
+
return fNext();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
_Fable.Orator.startService();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install orator-serviceserver-restify
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## How It Works
|
|
50
|
+
|
|
51
|
+
The Restify service server creates a Restify server instance in its constructor and delegates all route and middleware registration directly to it:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
Orator → serviceServer.get('/path', handler)
|
|
55
|
+
→ OratorServiceServerBase.get() [validates route]
|
|
56
|
+
→ OratorServiceServerRestify.doGet() [calls this.server.get()]
|
|
57
|
+
→ Restify server handles the route
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Accessing the Raw Restify Server
|
|
61
|
+
|
|
62
|
+
The underlying Restify server instance is available at `serviceServer.server`:
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const tmpRestifyServer = _Fable.Orator.serviceServer.server;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This gives you direct access to any Restify-specific features not exposed through the Orator interface.
|
|
69
|
+
|
|
70
|
+
## Related Packages
|
|
71
|
+
|
|
72
|
+
- [orator](https://github.com/stevenvelozo/orator) - Main Orator service abstraction
|
|
73
|
+
- [orator-serviceserver-base](https://github.com/stevenvelozo/orator-serviceserver-base) - Abstract base class
|
|
74
|
+
- [fable](https://github.com/stevenvelozo/fable) - Service provider framework
|
package/docs/_sidebar.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Body Parsing
|
|
2
|
+
|
|
3
|
+
The Restify service server uses Restify's built-in body parser plugin to parse incoming request bodies. There are two ways to use body parsing: per-route convenience methods and manual registration.
|
|
4
|
+
|
|
5
|
+
## Per-Route Body Parsing
|
|
6
|
+
|
|
7
|
+
The simplest approach is to use the `*WithBodyParser` convenience methods, which automatically inject the body parser middleware before your route handler:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
_Fable.Orator.serviceServer.postWithBodyParser('/api/items',
|
|
11
|
+
(pRequest, pResponse, fNext) =>
|
|
12
|
+
{
|
|
13
|
+
// pRequest.body is already parsed
|
|
14
|
+
let tmpNewItem = pRequest.body;
|
|
15
|
+
pResponse.send({ created: true, item: tmpNewItem });
|
|
16
|
+
return fNext();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
_Fable.Orator.serviceServer.putWithBodyParser('/api/items/:id',
|
|
20
|
+
(pRequest, pResponse, fNext) =>
|
|
21
|
+
{
|
|
22
|
+
let tmpUpdatedItem = pRequest.body;
|
|
23
|
+
pResponse.send({ updated: true, item: tmpUpdatedItem });
|
|
24
|
+
return fNext();
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Available for all HTTP verbs: `getWithBodyParser`, `postWithBodyParser`, `putWithBodyParser`, `delWithBodyParser`, `patchWithBodyParser`, `optsWithBodyParser`, `headWithBodyParser`.
|
|
29
|
+
|
|
30
|
+
## Global Body Parsing
|
|
31
|
+
|
|
32
|
+
To parse request bodies for all routes, register the body parser as middleware:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
_Fable.Orator.serviceServer.use(_Fable.Orator.serviceServer.bodyParser());
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Default Body Parser Configuration
|
|
39
|
+
|
|
40
|
+
The Restify body parser is configured with these defaults:
|
|
41
|
+
|
|
42
|
+
| Option | Default | Description |
|
|
43
|
+
|--------|---------|-------------|
|
|
44
|
+
| `maxBodySize` | `0` | Maximum body size (0 = unlimited) |
|
|
45
|
+
| `mapParams` | `false` | Do not map body parameters to `req.params` |
|
|
46
|
+
| `mapFiles` | `false` | Do not map file uploads |
|
|
47
|
+
| `overrideParams` | `false` | Do not override URL params with body params |
|
|
48
|
+
| `multiples` | `true` | Allow multiple file uploads |
|
|
49
|
+
| `hash` | `'sha1'` | Hash algorithm for file uploads |
|
|
50
|
+
|
|
51
|
+
## Content Types
|
|
52
|
+
|
|
53
|
+
The Restify body parser handles these content types automatically:
|
|
54
|
+
|
|
55
|
+
- `application/json` - Parsed as JSON
|
|
56
|
+
- `application/x-www-form-urlencoded` - Parsed as URL-encoded form data
|
|
57
|
+
- `multipart/form-data` - Parsed as multipart form data (file uploads)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
The Restify service server accepts configuration through Fable settings. Restify-specific options are passed in the `RestifyConfiguration` object.
|
|
4
|
+
|
|
5
|
+
## Configuration Lookup
|
|
6
|
+
|
|
7
|
+
The module checks for Restify configuration in this order:
|
|
8
|
+
|
|
9
|
+
1. `options.RestifyConfiguration` (service instantiation options)
|
|
10
|
+
2. `fable.settings.RestifyConfiguration` (Fable settings)
|
|
11
|
+
3. Empty object `{}` (default)
|
|
12
|
+
|
|
13
|
+
## Default Configuration
|
|
14
|
+
|
|
15
|
+
The module sets one default that Restify doesn't:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
{
|
|
19
|
+
maxParamLength: Number.MAX_SAFE_INTEGER
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This prevents Restify from truncating long URL parameters. Your `RestifyConfiguration` settings are merged on top of this default.
|
|
24
|
+
|
|
25
|
+
## Configuration Options
|
|
26
|
+
|
|
27
|
+
Any option accepted by `restify.createServer()` can be passed through `RestifyConfiguration`:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const _Fable = new libFable({
|
|
31
|
+
Product: 'MyAPIServer',
|
|
32
|
+
ServicePort: 8080,
|
|
33
|
+
RestifyConfiguration: {
|
|
34
|
+
strictNext: true,
|
|
35
|
+
maxParamLength: 500
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Setting | Type | Default | Description |
|
|
41
|
+
|---------|------|---------|-------------|
|
|
42
|
+
| `maxParamLength` | number | `Number.MAX_SAFE_INTEGER` | Maximum URL parameter length |
|
|
43
|
+
| `strictNext` | boolean | `false` | Require next() to be called in handlers |
|
|
44
|
+
| `name` | string | - | Server name (uses Restify default if not set) |
|
|
45
|
+
| `version` | string | - | API version string |
|
|
46
|
+
|
|
47
|
+
## Example: JSON Configuration File
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"Product": "MyAPIServer",
|
|
52
|
+
"ProductVersion": "2.0.0",
|
|
53
|
+
"ServicePort": 8080,
|
|
54
|
+
"RestifyConfiguration": {
|
|
55
|
+
"strictNext": true
|
|
56
|
+
},
|
|
57
|
+
"LogStreams": [
|
|
58
|
+
{ "level": "info" }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
```
|
package/docs/cover.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Orator ServiceServer Restify <small>2</small>
|
|
2
|
+
|
|
3
|
+
> Production HTTP service server for Orator, powered by Restify
|
|
4
|
+
|
|
5
|
+
- Full HTTP verb support with route handler chaining
|
|
6
|
+
- Restify pre and post-routing middleware
|
|
7
|
+
- Built-in body parser with multipart support
|
|
8
|
+
- Seamless integration with the Orator service lifecycle
|
|
9
|
+
|
|
10
|
+
[GitHub](https://github.com/stevenvelozo/orator-serviceserver-restify)
|
|
11
|
+
[Get Started](#orator-serviceserver-restify)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Pict Docuserve - Base Styles
|
|
3
|
+
============================================================================ */
|
|
4
|
+
|
|
5
|
+
/* Reset and base */
|
|
6
|
+
*, *::before, *::after {
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
html, body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
14
|
+
font-size: 16px;
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
color: #423D37;
|
|
17
|
+
background-color: #fff;
|
|
18
|
+
-webkit-font-smoothing: antialiased;
|
|
19
|
+
-moz-osx-font-smoothing: grayscale;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Typography */
|
|
23
|
+
h1, h2, h3, h4, h5, h6 {
|
|
24
|
+
margin-top: 0;
|
|
25
|
+
line-height: 1.3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: #2E7D74;
|
|
30
|
+
text-decoration: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
a:hover {
|
|
34
|
+
color: #256861;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Application container */
|
|
38
|
+
#Docuserve-Application-Container {
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Utility: scrollbar styling */
|
|
43
|
+
::-webkit-scrollbar {
|
|
44
|
+
width: 8px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
::-webkit-scrollbar-track {
|
|
48
|
+
background: #F5F0E8;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::-webkit-scrollbar-thumb {
|
|
52
|
+
background: #D4CCBE;
|
|
53
|
+
border-radius: 4px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
::-webkit-scrollbar-thumb:hover {
|
|
57
|
+
background: #B5AA9A;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Responsive adjustments */
|
|
61
|
+
@media (max-width: 768px) {
|
|
62
|
+
html {
|
|
63
|
+
font-size: 14px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#Docuserve-Sidebar-Container {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.docuserve-body {
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install fable orator orator-serviceserver-restify
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
The Restify service server is registered with Fable as the `OratorServiceServer` service type. Orator will use it automatically once it's instantiated:
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
const libFable = require('fable');
|
|
15
|
+
const libOrator = require('orator');
|
|
16
|
+
const libOratorServiceServerRestify = require('orator-serviceserver-restify');
|
|
17
|
+
|
|
18
|
+
const _Fable = new libFable({
|
|
19
|
+
Product: 'MyAPIServer',
|
|
20
|
+
ProductVersion: '1.0.0',
|
|
21
|
+
ServicePort: 8080
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Register service types
|
|
25
|
+
_Fable.serviceManager.addServiceType('Orator', libOrator);
|
|
26
|
+
_Fable.serviceManager.addServiceType('OratorServiceServer', libOratorServiceServerRestify);
|
|
27
|
+
|
|
28
|
+
// Instantiate (order doesn't matter -- Orator finds the service server during initialization)
|
|
29
|
+
_Fable.serviceManager.instantiateServiceProvider('Orator');
|
|
30
|
+
_Fable.serviceManager.instantiateServiceProvider('OratorServiceServer');
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Defining Routes
|
|
34
|
+
|
|
35
|
+
Register route handlers on the service server using standard HTTP verb methods:
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
const tmpServiceServer = _Fable.Orator.serviceServer;
|
|
39
|
+
|
|
40
|
+
// GET request
|
|
41
|
+
tmpServiceServer.get('/api/items',
|
|
42
|
+
(pRequest, pResponse, fNext) =>
|
|
43
|
+
{
|
|
44
|
+
pResponse.send([{ id: 1, name: 'Item One' }]);
|
|
45
|
+
return fNext();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// GET with URL parameters
|
|
49
|
+
tmpServiceServer.get('/api/items/:id',
|
|
50
|
+
(pRequest, pResponse, fNext) =>
|
|
51
|
+
{
|
|
52
|
+
pResponse.send({ id: pRequest.params.id });
|
|
53
|
+
return fNext();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// POST with body parsing
|
|
57
|
+
tmpServiceServer.postWithBodyParser('/api/items',
|
|
58
|
+
(pRequest, pResponse, fNext) =>
|
|
59
|
+
{
|
|
60
|
+
let tmpNewItem = pRequest.body;
|
|
61
|
+
pResponse.send({ created: true, item: tmpNewItem });
|
|
62
|
+
return fNext();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// PUT with body parsing
|
|
66
|
+
tmpServiceServer.putWithBodyParser('/api/items/:id',
|
|
67
|
+
(pRequest, pResponse, fNext) =>
|
|
68
|
+
{
|
|
69
|
+
pResponse.send({ updated: true, id: pRequest.params.id });
|
|
70
|
+
return fNext();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// DELETE
|
|
74
|
+
tmpServiceServer.del('/api/items/:id',
|
|
75
|
+
(pRequest, pResponse, fNext) =>
|
|
76
|
+
{
|
|
77
|
+
pResponse.send({ deleted: true });
|
|
78
|
+
return fNext();
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Starting the Server
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
_Fable.Orator.startService(
|
|
86
|
+
() =>
|
|
87
|
+
{
|
|
88
|
+
_Fable.log.info('Server is ready');
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Stopping the Server
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
_Fable.Orator.stopService(
|
|
96
|
+
() =>
|
|
97
|
+
{
|
|
98
|
+
_Fable.log.info('Server stopped');
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Next Steps
|
|
103
|
+
|
|
104
|
+
- [Configuration](configuration.md) - Customize the Restify server
|
|
105
|
+
- [Middleware](middleware.md) - Add request processing middleware
|
|
106
|
+
- [Body Parsing](body-parsing.md) - Configure request body parsing
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
+
<meta name="description" content="Documentation powered by pict-docuserve">
|
|
8
|
+
|
|
9
|
+
<title>Documentation</title>
|
|
10
|
+
|
|
11
|
+
<!-- Application Stylesheet -->
|
|
12
|
+
<link href="css/docuserve.css" rel="stylesheet">
|
|
13
|
+
<!-- KaTeX stylesheet for LaTeX equation rendering -->
|
|
14
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
|
|
15
|
+
<!-- PICT Dynamic View CSS Container -->
|
|
16
|
+
<style id="PICT-CSS"></style>
|
|
17
|
+
|
|
18
|
+
<!-- Load the PICT library from jsDelivr CDN -->
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
|
|
20
|
+
<!-- Bootstrap the Application -->
|
|
21
|
+
<script type="text/javascript">
|
|
22
|
+
//<![CDATA[
|
|
23
|
+
Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
|
|
24
|
+
//]]>
|
|
25
|
+
</script>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<!-- The root container for the Pict application -->
|
|
29
|
+
<div id="Docuserve-Application-Container"></div>
|
|
30
|
+
|
|
31
|
+
<!-- Mermaid diagram rendering -->
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
33
|
+
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
|
34
|
+
<!-- KaTeX for LaTeX equation rendering -->
|
|
35
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
|
|
36
|
+
<!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Middleware
|
|
2
|
+
|
|
3
|
+
The Restify service server supports two types of middleware, matching Restify's own middleware pipeline.
|
|
4
|
+
|
|
5
|
+
## Post-Routing Middleware (use)
|
|
6
|
+
|
|
7
|
+
Middleware registered with `use()` runs after the route has been matched but before the route handler executes:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
_Fable.Orator.serviceServer.use(
|
|
11
|
+
(pRequest, pResponse, fNext) =>
|
|
12
|
+
{
|
|
13
|
+
_Fable.log.trace(`${pRequest.method} ${pRequest.url}`);
|
|
14
|
+
return fNext();
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This is the standard middleware pattern. The base class validates that the parameter is a function, then the Restify implementation passes it to the underlying Restify server's `use()` method.
|
|
19
|
+
|
|
20
|
+
## Pre-Routing Middleware (pre)
|
|
21
|
+
|
|
22
|
+
Middleware registered with `pre()` runs before the route is even matched. This is useful for things like request sanitization, CORS headers, or URL rewriting:
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
_Fable.Orator.serviceServer.pre(
|
|
26
|
+
(pRequest, pResponse, fNext) =>
|
|
27
|
+
{
|
|
28
|
+
// Runs before routing
|
|
29
|
+
return fNext();
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Middleware Order
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Incoming Request
|
|
37
|
+
↓
|
|
38
|
+
pre() middleware (before routing)
|
|
39
|
+
↓
|
|
40
|
+
Route Matching
|
|
41
|
+
↓
|
|
42
|
+
use() middleware (after routing)
|
|
43
|
+
↓
|
|
44
|
+
Route Handler(s)
|
|
45
|
+
↓
|
|
46
|
+
Response
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Example: Request Logging
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
_Fable.Orator.serviceServer.use(
|
|
53
|
+
(pRequest, pResponse, fNext) =>
|
|
54
|
+
{
|
|
55
|
+
let tmpStartTime = Date.now();
|
|
56
|
+
|
|
57
|
+
pResponse.on('finish',
|
|
58
|
+
() =>
|
|
59
|
+
{
|
|
60
|
+
let tmpDuration = Date.now() - tmpStartTime;
|
|
61
|
+
_Fable.log.info(`${pRequest.method} ${pRequest.url} ${pResponse.statusCode} ${tmpDuration}ms`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return fNext();
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Example: CORS Headers
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
_Fable.Orator.serviceServer.pre(
|
|
72
|
+
(pRequest, pResponse, fNext) =>
|
|
73
|
+
{
|
|
74
|
+
pResponse.header('Access-Control-Allow-Origin', '*');
|
|
75
|
+
pResponse.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
|
|
76
|
+
pResponse.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
77
|
+
return fNext();
|
|
78
|
+
});
|
|
79
|
+
```
|