Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 0 additions & 67 deletions .eslintrc

This file was deleted.

31 changes: 31 additions & 0 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: pr-validation

on:
pull_request:
branches:
- '*'

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [22.x, 24.x]

steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install, build, and test
run: |
npm i
npm run build
npm run lint
npm run test
npm run bench
env:
CI: true
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,10 @@ api_docs
/benchmarks/compare.js
yarn.lock
package-lock.json
.clinic
.clinic

# Build output
dist/

# TypeScript
*.tsbuildinfo
9 changes: 0 additions & 9 deletions .npmignore

This file was deleted.

6 changes: 0 additions & 6 deletions .travis.yml

This file was deleted.

215 changes: 113 additions & 102 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,146 +1,157 @@
<h1 align="center">
<a title="Schema based serialization made easy" href="http://compactr.js.org">
<a title="OpenAPI serialization" href="http://compactr.js.org">
<img alt="Compactr" width="320px" src="http://res.cloudinary.com/kalm/image/upload/v1494589244/compactr_header_rev1.png" />
<br/><br/>
</a>
Compactr
</h1>
<h3 align="center">
Schema based serialization made easy
OpenAPI serialization
<br/><br/><br/>
</h3>
<br/>

[![Compactr](https://img.shields.io/npm/v/compactr.svg)](https://www.npmjs.com/package/compactr)
[![Build Status](https://travis-ci.org/compactr/compactr.js.svg?branch=master)](https://travis-ci.org/compactr/compactr.js)
[![Gitter](https://img.shields.io/gitter/room/compactr/compactr.svg)](https://gitter.im/compactr/compactr)

---

## What is this and why does it matter?

Protocol Buffers are awesome. Having schemas to deflate and inflate data while maintaining some kind of validation is a great concept. Compactr's goal is to build on that to better suit the Javascript ecosystem.

[More](docs/ABOUT.md)

- **OpenAPI 3.x Compatible** Use your existing OpenAPI schemas, no extra definitions required
- **Cuts bandwidth in half** Average API responses are multiple times smaller than JSON
- **Built for actual APIs** Specialty field types to optimize common items, ex: UUID, date-time, ivp4
- **Zero dependencies** and can be bundled down to ~5kb!

## Install

```bash
npm install compactr
```
npm install compactr
```


## Implementation
## Usage

```node
### Basic Example

const Compactr = require('compactr');
```typescript
import { schema } from 'compactr';

// Defining a schema
const userSchema = Compactr.schema({
id: { type: 'number' },
name: { type: 'string' }
const userSchema = schema({
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
name: { type: 'string' },
age: { type: 'integer', format: 'int32' },
balance: { type: 'number', format: 'double' },
created: { type: 'string', format: 'date-time' },
tags: { type: 'array', items: { type: 'string' } }
}
});

const data = {
id: '550e8400-e29b-4d4e-a7d4-426614174000',
name: 'Alice',
age: 30,
balance: 1234.56,
created: '2025-10-28T14:30:00.000Z',
tags: ['premium', 'verified']
};

const buffer = userSchema.write(data);
const decoded = userSchema.read(buffer);
```

Compactr also supports component references ($ref).

*Only local references are allowed*

**Component References**

```typescript
const schema = schema(
{
user: { $ref: '#/User' },
product: { $ref: '#/Product' }
},
{
schemas: {
User: {
type: 'object',
properties: {
id: { type: 'integer', format: 'int32' },
name: { type: 'string' }
}
},
Product: {
type: 'object',
properties: {
sku: { type: 'string' },
price: { type: 'number', format: 'double' }
}
}
}
}
);
```

// Encoding
userSchema.write({ id: 123, name: 'John' });

// Get the header bytes
const header = userSchema.headerBuffer();

// Get the content bytes
const partial = userSchema.contentBuffer();
## Supported Types

// Get the full payload (header + content bytes)
const buffer = userSchema.buffer();
Compactr supports the following OpenAPI types and formats:

| Type | Format | Bytes | Description |
| --- | --- | --- | --- |
| boolean | - | 1 | Boolean value |
| integer | int32 | 4 | 32-bit integer |
| integer | int64 | 8 | 64-bit integer |
| number | float | 4 | 32-bit floating point |
| number | double | 8 | 64-bit floating point |
| string | - | 2/char | UTF-8 string |
| string | uuid | 16 | UUID (compressed) |
| string | ipv4 | 4 | IPv4 address |
| string | ipv6 | 16 | IPv6 address |
| string | date | 4 | Date (YYYY-MM-DD) |
| string | date-time | 8 | ISO 8601 date-time |
| string | binary | variable | Base64 binary data |
| array | - | variable | Array of items |
| object | - | variable | Nested object |


## Performance

// Decoding a full payload
const content = userSchema.read(buffer);
I realistic scenarios, compactr performs a bit slower than JSON.stringify/ JSON.parse as well as `protobuf`, but can yield a byte reduction of 3.5x compared to JSON.

// Decoding a partial payload (content)
const content = userSchema.readContent(partial);
```
[JSON-API Reponse] JSON x 379 ops/sec ±0.66% (92 runs sampled)
[JSON-API Reponse] Compactr x 167 ops/sec ±0.75% (85 runs sampled)
[JSON-API Reponse] Protobuf x 358 ops/sec ±1.36% (91 runs sampled)
[JSON-API Reponse] MsgPack x 161 ops/sec ±2.06% (79 runs sampled)

## Size comparison

JSON: `{"id":123,"name":"John"}`: 24 bytes

Compactr (full): `<Buffer 02 00 01 01 04 7b 4a 6f 68 6e>`: 10 bytes

Compactr (partial): `<Buffer 7b 4a 6f 68 6e>`: 5 bytes

Buffer size (bytes): { json: 277, compactr: 80, protobuf: 129, msgpack: 227 }
```

## Protocol details
## Testing

### Data types
Run the test suite:

Type | Count bytes | Byte size
--- | --- | ---
boolean | 0 | 1
number | 0 | 8
int8 | 0 | 1
int16 | 0 | 2
int32 | 0 | 4
double | 0 | 8
string | 1 | 2/char
char8 | 1 | 1/char
char16 | 1 | 2/char
char32 | 1 | 4/char
array | 1 | (x)/entry
object | 1 | (x)
unsigned | 0 | 8
unsigned8 | 0 | 1
unsigned16 | 0 | 2
unsigned32 | 0 | 4
```bash
npm test
```

* Count bytes range can be specified per-item in the schema*
Run benchmarks:

See the full [Compactr protocol](https://github.com/compactr/protocol)
```bash
npm run bench
```

## Benchmarks
Build the project:

```
[Array] JSON x 737 ops/sec ±1.04% (91 runs sampled)
[Array] Compactr x 536 ops/sec ±1.25% (82 runs sampled)
[Array] size: { json: 0, compactr: 10 }

[Boolean] JSON x 996 ops/sec ±0.84% (93 runs sampled)
[Boolean] Compactr x 1,439 ops/sec ±1.24% (83 runs sampled)
[Boolean] Protobuf x 2,585 ops/sec ±1.32% (91 runs sampled)
[Boolean] size: { json: 23, compactr: 5, protobuf: 5 }

[Float] JSON x 713 ops/sec ±1.29% (88 runs sampled)
[Float] Compactr x 1,056 ops/sec ±1.38% (86 runs sampled)
[Float] Protobuf x 2,432 ops/sec ±1.45% (88 runs sampled)
[Float] size: { json: 41, compactr: 12, protobuf: 12 }

[Integer] JSON x 954 ops/sec ±0.77% (93 runs sampled)
[Integer] Compactr x 1,520 ops/sec ±1.21% (89 runs sampled)
[Integer] Protobuf x 2,676 ops/sec ±1.22% (90 runs sampled)
[Integer] size: { json: 24, compactr: 8, protobuf: 7 }

[Object] JSON x 512 ops/sec ±0.62% (90 runs sampled)
[Object] Compactr x 412 ops/sec ±1.46% (81 runs sampled)
[Object] Protobuf x 898 ops/sec ±0.92% (93 runs sampled)
[Object] size: { json: 46, compactr: 13, protobuf: 25 }

[String] JSON x 432 ops/sec ±0.79% (88 runs sampled)
[String] Compactr x 428 ops/sec ±0.87% (87 runs sampled)
[String] Protobuf x 738 ops/sec ±0.71% (90 runs sampled)
[String] size: { json: 57, compactr: 14, protobuf: 28 }
```bash
npm run build
```

## Want to help ?
## Contributing

You are awesome! Open an issue on this project, identifying the feature that you want to tackle and we'll take the discussion there!
Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License
## License

[Apache 2.0](LICENSE) (c) 2020 Frederic Charette
[Apache 2.0](LICENSE) (c) 2025 Frederic Charette
Loading