Skip to content

Commit

Permalink
feat: start writing docs and API Reference for Data
Browse files Browse the repository at this point in the history
  • Loading branch information
TillaTheHun0 committed Jan 1, 2024
1 parent 9b78d76 commit 8ccc2ea
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 10 deletions.
20 changes: 14 additions & 6 deletions src/.vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,31 @@ export default defineConfig({
text: 'Clean Cloud Architecture',
link: '/docs/concepts/clean-cloud-architecture',
},
{
text: 'hyper Response Shape',
link: '/docs/concepts/hyper-shape',
},
],
},
{
text: '🛠 Build',
link: '/docs/build/index',
items: [
{
text: 'Custom Adapter',
link: '/docs/build/custom-adapter',
text: '🔐 Securing hyper',
link: '/docs/build/securing-hyper'
},
{
text: 'Custom App',
link: '/docs/build/custom-app',
text: 'Custom Middleware',
link: '/docs/build/custom-middleware',
},
{
text: 'Custom Middleware',
link: '/docs/build/custom-middleware',
text: '🪗 Custom Adapter',
link: '/docs/build/custom-adapter',
},
{
text: '📲 Custom App',
link: '/docs/build/custom-app',
},
],
},
Expand Down
104 changes: 104 additions & 0 deletions src/docs/api-reference/rest/data.md
Original file line number Diff line number Diff line change
@@ -1 +1,105 @@
# hyper `Data` Service

A hyper Data service is a document data store for storing JSON documents. List, query, add, update, and delete documents. You can also create indexes to improve query performance.

:::info
Be sure to include any appropriate authN/Z on the request. See [Securing your hyper `Server`](/docs/build/securing-hyper)
:::

[[toc]]

## Create a `Data` Service

Create a hyper `Data` Service in the [`Domain`](/docs/concepts/terminology#domain).

::: code-group

```js [node.js]
import { connect } from "hyper-connect";

const { data } = connect(process.env.HYPER);

await data.create(); // { ok: true }
```

```sh [curl]
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X PUT https://$HOST/data/$DOMAIN
```

:::

### Common Responses

| Status | Description | Response |
| ------ | :-------------------------------: | ---------------------------: |
| 201 | The `Data` Service was created | `{ ok: true }` |
| 409 | The `Data` Service already exists | `{ ok: false, status: 409 }` |

## Create a Document

Store a Document in the `Data` Service.

A hyper `Data` Service document is a JSON document with one to many fields. An `_id` field is allowed. If an `_id` is not provided, it will be generated by the hyper `Server`. The `_id` field MUST be unique.

:::tip
We recommend providing your own `_id`, when creating a document, that is appropriate for your use-case.
:::

::: code-group

```js [node.js]
import { connect } from 'hyper-connect'

const { data } = connect(process.env.HYPER)

await data.add({ _id: "...", ... }) // { ok: true, id: "..." }
```

```sh [curl]
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X POST https://$HOST/data/$DOMAIN
```

:::

### Common Responses

| Status | Description | Response |
| ------ | :---------------------------------------: | ---------------------------: |
| 201 | The document was created | `{ ok: true, id: '...' }` |
| 409 | A document with that `_id` already exists | `{ ok: false, status: 409 }` |

## Retrieve a Document

Retrieve a document from a `Data` Service by `_id`

::: code-group

```js [node.js]
import { connect } from "hyper-connect";

const { data } = connect(process.env.HYPER);

await data.get("..."); // { ok: true, doc: { ... } }
```

```sh [curl]
export HOST="hyper.host"
export DOMAIN="foobar"

curl -X GET https://$HOST/data/$DOMAIN/$ID
```

:::

### Common Responses

| Status | Description | Response |
| ------ | :----------------------------------------------------------------------------: | ---------------------------: |
| 200 | The document was retrieved | `{ ok: true, doc: { ... } }` |
| 404 | A document with that `_id` does not exist or the `Data` Service does not exist | `{ ok: false, status: 404 }` |
12 changes: 8 additions & 4 deletions src/docs/api-reference/rest/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ Server framework [express](https://expressjs.com/).
This hyper `App` exposes each of the core hyper Services as a set of REST resources:

- [`Data`](data): hyper `Data` Services available on the hyper `Server`
- [`Cache`](data): hyper `Cache` Services available on the hyper `Server`
- [`Storage`](data): hyper `Storage` Services available on the hyper `Server`
- [`Queue`](data): hyper `Queue` Services available on the hyper `Server`
- [`Search`](data): hyper `Search` Services available on the hyper `Server`
- [`Cache`](cache): hyper `Cache` Services available on the hyper `Server`
- [`Storage`](storage): hyper `Storage` Services available on the hyper `Server`
- [`Queue`](queue): hyper `Queue` Services available on the hyper `Server`
- [`Search`](search): hyper `Search` Services available on the hyper `Server`

:::tip
Be sure to include any appropriate authN/Z on the request. See [Securing your hyper `Server`](/docs/build/securing-hyper)
:::
2 changes: 2 additions & 0 deletions src/docs/build/custom-adapter.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Build a Custom hyper Driven Adapter

TODO
2 changes: 2 additions & 0 deletions src/docs/build/custom-app.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Build a Custom hyper Driving Adapter aka. "App"

TODO
2 changes: 2 additions & 0 deletions src/docs/build/custom-middleware.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Build a Custom hyper App Middleware

TODO
92 changes: 92 additions & 0 deletions src/docs/build/securing-hyper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Securing your hyper Server

In most cases, the hyper Server will need to validate incoming requests, so as to prevent unwanted access to hyper `Services` running on the hyper `Server`.

A common practice is to add [Custom Middleware](/docs/build/custom-middleware) to the hyper Config that is added to the hyper `Server` and enforces the AuthN/Z desired. For example, when using an HTTP based hyper `App`, a `Custom Middleware` could be used to check and verify incoming requests, perhaps a `Bearer` token in the `Authorization` header.

Here is what that middleware might look like, when using the pre-built App [`app-express`](https://github.com/hyper63/hyper/tree/main/packages/app-express):

::: code-group

```ts [hyper.config.ts]
import { appExpress, hyper, type express } from './deps.ts'
/**
* Given a sub and secret, return a hyper Custom Middleware that will
* check that all incoming requests have a properly signed jwt token
* in the Authorization header as a bearer token
*/
const authMiddleware =
({ sub, secret }: { sub: string; secret: string }) =>
(app: express.Express) => {
/**
* Extract the bearer token from the header, and verify it's
* signature and sub matches expected
*/
const verify = async (header: string) => {
const payload = await jwt
.verify(header.split(' ').pop() as string, secret, 'HS256')
.catch(() => {
throw { name: 'UnauthorizedError' }
})
/**
* Confirm sub matches
*/
if (payload.sub !== sub) throw { name: 'UnauthorizedError' }
}

app.use(async (req, _res, next) => {
await verify(req.get('authorization') || 'Bearer notoken')
.then(() => next())
// pass error to next, triggering the next error middleware to take over
.catch(next)
})

app.use(
(
err: unknown,
_req: express.Request,
res: express.Response,
next: express.NextFunction
): unknown => {
if (err && err.name === 'UnauthorizedError') {
return res.status(401).send({ ok: false, msg: 'not authorized' })
}
// Trigger the next error handler
next(err)
}
)

return app
}

export default hyper({
app,
adapters: [...],
/**
* Add the custom middleware in the hyper Server configuration
*/
middleware: [authMiddleware({ sub: Deno.env.get('SUB'), secret: Deno.env.get('SECRET') })]
})
```

:::

This is by-far the most common approach for securing an HTTP-based hyper `Server`.

## Connection String with `hyper-connect`

Because the above approach is so common, `hyper-connect` ships with the ability to automatically generate short-lived JSON Web Tokens (JWTs) using the credentials provided in the `connection string`.

```js
import { connect } from 'hyper-connect'

const { data } = connect('https://user:[email protected]/foobar')

/**
* hyper-connect will automatically generate a JWT, whose sub is "user"
* and is signed using "password" and the HS256 algorithm
*/
await data.add({...})
```

No matter which way you secure your hyper `Server`, make sure you include the appropriate credentials when consuming it.
2 changes: 2 additions & 0 deletions src/docs/concepts/clean-cloud-architecture.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Clean Cloud Architecture

TODO
24 changes: 24 additions & 0 deletions src/docs/concepts/hyper-shape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# hyper Response Shape

Most hyper APIs will return a "hyper" shape like the following:

```ts
interface HyperResult = {
ok: boolean,
status?: number,
msg?: string
}
```

`ok` is always provided and is `true` if the operation was successful, and `false` if the operation was not successful. When `ok` is `true`, there MAY be additional fields on the result, which depends on the specific operation being performed (see [API Reference](/docs/api-reference/index)). When `ok` is `false`, An optional `status` and `msg` can be included to provide additional context.

> The hyper `Server` does not enforce any semantics on `status` or `msg`, besides their types. It is up the hyper `Service` Adapter to set `status` and/or `msg`. When an error occurs, a common paradigm for adapters is to use an HTTP status code for `status`, and `msg` as a free text field to provided additional context.
## `hyper-connect` and the hyper Response Shape

`hyper-connect` will NOT throw unless:

- A network error occurs, for example a TCP connection being dropped
- A `5xx` status code is received from the hyper `Server`

This means your business logic SHOULD check `ok` property and subsequently `status` and `msg` (checking `status` is most common) in the resolved result. **This is by design**, as it encourages business logic to handle sad paths when interacting with the services tier.
2 changes: 2 additions & 0 deletions src/docs/concepts/ports-and-adapters.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Ports and Adapters

TODO
3 changes: 3 additions & 0 deletions src/docs/concepts/why.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Why hyper

TODO
2 changes: 2 additions & 0 deletions src/docs/host/hyper-config.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# The `hyper` Config File

TODO
2 changes: 2 additions & 0 deletions src/docs/host/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# Hosting a hyper Server

TODO

0 comments on commit 8ccc2ea

Please sign in to comment.