Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
DASPRiD committed Feb 9, 2024
0 parents commit fda692c
Show file tree
Hide file tree
Showing 55 changed files with 5,443 additions and 0 deletions.
47 changes: 47 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Release

on:
push:
branches:
- main

jobs:
release:
name: Release
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Use pnpm 8.x
uses: pnpm/action-setup@v2
with:
version: 8

- name: Use Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20
cache: 'pnpm'

- name: Install Dependencies
run: pnpm install

- name: Biome CI
run: pnpm exec biome ci .

- name: Build
run: pnpm build

- name: Semantic Release
uses: cycjimmy/semantic-release-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
HUSKY: 0
id: semantic
with:
semantic_version: 19.0.5
extra_plugins: |
@semantic-release/[email protected]
@semantic-release/[email protected]
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/cdk.out
/node_modules
/dist
1 change: 1 addition & 0 deletions .lefthook/commit-msg/commitlint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
echo $(head -n1 $1) | npx commitlint --color
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Copyright (c) 2023, Ben Scholzen 'DASPRiD'
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# JSON:API support for Koa with Zod

[![Release](https://github.com/DASPRiD/koa-jsonapi-zod/actions/workflows/release.yml/badge.svg)](https://github.com/DASPRiD/mikro-orm-js-joda/actions/workflows/release.yml)

This package provides support for working with JSON:API in Koa, taking all guesswork out of the equation.

## Installation

### npm
```bash
npm i koa-jsonapi-zod
```

### pnpm
```bash
pnpm add koa-jsonapi-zod
```

## Usage

In order to serialize your entities into valid JSON:API responses, you have to set up a serialize manager which is
composed of several entity serializers. You also have access to several utility functions meant for parsing incoming
requests, as well as a middleware which takes care of handling requests and responses.

For a complete example, have a look under [examples/complete](examples/complete).

### Middlewares

This package exports two middlewares, `jsonApiRequestMiddleware` and `jsonApiErrorMiddleware`.

The former takes care of validating incoming requests and formatting responses accordingly. You can exclude specific
paths from being handled by the middleware (e.g. RPC endpoints). This middleware should be registered as early as
possible.

The error middleware is a convenience middleware which traps all errors and creates appropriate error responses. You
can also supply a logger function as an option, which allows you to log specific errors. This middleware should be
registered right after the request middleware.

For more details, see `index.ts` in the complete example.

### Features not covered in the example

#### Serialization context

In some instances your serializers might require context about a request. One instance of this is where you want to
expose specific fields of an entity only when the user has permission to access these. In that case you should define
your serialization context first:

```typescript
type SerializerContext = {
permissions?: string[];
};
```

You can the define that context as generic parameter in both the `SerializeManager` as well as your `EntitySerializer`
instances. Since the context is always an optional property, you can then perform checks like this in e.g. your
`getAttributes()` implementation:

```typescript
const attributes: Record<string, unknown> = {
foo: "bar",
baz: "bat",
};

if (options.context?.permissions?.includes("read:secret")) {
attributes.secret = "super secrtet information";
}
```

#### Filtering

You can add filters to list handlers as well. JSON:API does not define the structure of filters itself, except that the
`filter` property should be used for this. Whether you make that property an object or a plain string is up to you.
Simply provide a `Zod` schema to the `filterSchema` property, and you will get a `filter` property on the result back.

#### Pagination

Similar to filters you can also supply a `pageSchema` property, which will result in a `page` result.
56 changes: 56 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"$schema": "https://biomejs.dev/schemas/1.5.2/schema.json",
"organizeImports": {
"enabled": true
},
"files": {
"include": [
"biome.json",
"commitlint.config.cjs",
"release.config.cjs",
"src/**/*",
"examples/*/src/**/*"
]
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"nursery": {
"noEmptyTypeParameters": "error",
"noInvalidUseBeforeDeclaration": "error",
"noUnusedImports": "error",
"noUnusedPrivateClassMembers": "error",
"noUselessLoneBlockStatements": "error",
"noUselessTernary": "error",
"useExportType": "error",
"useImportType": "error",
"useForOf": "error",
"useGroupedTypeImport": "error"
},
"complexity": {
"noExcessiveCognitiveComplexity": "warn",
"useSimplifiedLogicExpression": "error"
},
"correctness": {
"noNewSymbol": "error"
},
"style": {
"useBlockStatements": "error",
"useCollapsedElseIf": "error",
"useShorthandArrayType": "error",
"useShorthandAssign": "error",
"useSingleCaseStatement": "error"
},
"suspicious": {
"noApproximativeNumericConstant": "warn",
"noConsoleLog": "error"
}
}
},
"formatter": {
"indentStyle": "space",
"indentWidth": 4,
"lineWidth": 100
}
}
1 change: 1 addition & 0 deletions commitlint.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { extends: ["@commitlint/config-conventional"] };
6 changes: 6 additions & 0 deletions examples/complete/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Complete Example

This is a complete example showcasing all features of `koa-jsonapi-zod`. It utilizes Mikro ORM as data source, but you
can of course use any other data source.

To run the example, simply execute `pnpm start`.
17 changes: 17 additions & 0 deletions examples/complete/node_modules/.bin/flat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions examples/complete/node_modules/.bin/tsc

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions examples/complete/node_modules/.bin/tsserver

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions examples/complete/node_modules/.bin/tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@js-joda/core

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@mikro-orm/core

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@mikro-orm/sqlite

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@types/http-errors

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@types/koa

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/@types/koa-bodyparser

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/flat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/http-errors

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/koa

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/koa-bodyparser

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/koa-jsonapi-zod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/koa-tree-router

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/mikro-orm-js-joda

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/typescript

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/complete/node_modules/zod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions examples/complete/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "complete",
"type": "module",
"dependencies": {
"@js-joda/core": "^5.6.1",
"@mikro-orm/core": "^6.1.0",
"@mikro-orm/sqlite": "^6.1.0",
"flat": "^6.0.1",
"http-errors": "^2.0.0",
"koa": "^2.15.0",
"koa-bodyparser": "^4.4.1",
"koa-jsonapi-zod": "workspace:*",
"koa-tree-router": "^0.12.1",
"mikro-orm-js-joda": "^1.0.1",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/http-errors": "^2.0.4",
"@types/koa": "^2.14.0",
"@types/koa-bodyparser": "^4.3.12",
"tsx": "^4.7.0",
"typescript": "^5.3.3"
},
"scripts": {
"start": "tsx watch src/index.ts"
}
}
28 changes: 28 additions & 0 deletions examples/complete/src/entity/Article.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { randomUUID } from "crypto";
import { ZonedDateTime } from "@js-joda/core";
import { Entity, ManyToOne, PrimaryKey, Property, type Ref, Reference, t } from "@mikro-orm/core";
import { ZonedDateTimeType } from "mikro-orm-js-joda";
import { Person } from "./Person.js";

@Entity()
export class Article {
@PrimaryKey({ type: t.uuid })
public readonly id: string = randomUUID();

@Property({ type: ZonedDateTimeType })
public readonly createdAt = ZonedDateTime.now();

@Property({ type: ZonedDateTimeType, onUpdate: () => ZonedDateTime.now() })
public readonly updatedAt = ZonedDateTime.now();

@Property({ type: t.text })
public title: string;

@ManyToOne(() => Person, { ref: true })
public author: Ref<Person>;

public constructor(title: string, author: Person) {
this.title = title;
this.author = Reference.create(author);
}
}
Loading

0 comments on commit fda692c

Please sign in to comment.