Skip to content
Open
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
83 changes: 83 additions & 0 deletions packages/http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,89 @@

This is the middleware pipeline and HTTP kernel system for the [H3ravel](https://h3ravel.toneflix.net) framework.

## API Resources

H3ravel provides `Resource` and `Collection` classes to standardize JSON API responses.

### Single Resource

```ts
import { Resource } from '@h3ravel/http'

const user = { id: 1, name: 'Alice' }
const userResource = new Resource(user)

console.log(userResource.toArray())
// Output: { id: 1, name: 'Alice' }
```

### Resource with Relationships

```ts
const user = { id: 1, name: 'Alice', posts: [{ id: 10, title: 'Hello' }] }
const userResource = new Resource(user).withRelation('posts', user.posts)

console.log(userResource.toArray())
// Output: { id: 1, name: 'Alice', posts: [{ id: 10, title: 'Hello' }] }
```

### Collection of Resources

```ts
import { Collection, Resource } from '@h3ravel/http'

const users = [new Resource({ id: 1 }), new Resource({ id: 2 })]
const collection = new Collection(users)
.withPagination({ from: 1, to: 2, total: 10, perPage: 2 })
.withLinks({ self: '/users', next: '/users?page=2' })

console.log(collection.toArray())
// Output: [{ id: 1 }, { id: 2 }]

console.log(collection.json())
/* Output:
{
data: [{ id: 1 }, { id: 2 }],
meta: { pagination: { from: 1, to: 2, total: 10, perPage: 2 } },
links: { self: '/users', next: '/users?page=2' }
}
*/
```

### JsonResource (HTTP Response)

```ts
import { JsonResource } from '@h3ravel/http'

const jsonRes = new JsonResource({ req: {}, res: { status: 200 } } as any, collection).json()

console.log(jsonRes.body)
/* Output:
{
data: [{ id: 1 }, { id: 2 }],
meta: { pagination: { from: 1, to: 2, total: 10, perPage: 2 } },
links: { self: '/users', next: '/users?page=2' }
}
*/
```

### Additional Features

You can add extra fields to the JSON response with additional():

```ts
jsonRes.additional({ message: 'Fetched successfully' })
console.log(jsonRes.body)
/* Output:
{
data: [{ id: 1 }, { id: 2 }],
meta: { pagination: { from: 1, to: 2, total: 10, perPage: 2 } },
links: { self: '/users', next: '/users?page=2' },
message: 'Fetched successfully'
}
*/
```

## Contributing

Thank you for considering contributing to the H3ravel framework! The [Contribution Guide](https://h3ravel.toneflix.net/contributing) can be found in the H3ravel documentation and will provide you with all the information you need to get started.
Expand Down
76 changes: 76 additions & 0 deletions packages/http/src/Resources/Collection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { Resource } from './Resource'

export interface CollectionMeta {
pagination?: {
from?: number
to?: number
perPage?: number
total?: number
}
[key: string]: any
}

export interface CollectionLinks {
self?: string
next?: string
prev?: string
[key: string]: any
}

export class Collection<T = any> {
protected items: (T | Resource)[]
protected meta: CollectionMeta = {}
protected links: CollectionLinks = {}

/**
* Accept items, optional pagination, and optional links
*/
constructor(
items: (T | Resource)[] = [],
pagination?: CollectionMeta['pagination'],
links?: CollectionLinks
) {
this.items = items
if (pagination) this.meta.pagination = pagination
if (links) this.links = links
}

/**
* Set pagination metadata
*/
withPagination(pagination: CollectionMeta['pagination']): this {
this.meta.pagination = pagination
return this
}

/**
* Set links metadata
*/
withLinks(links: CollectionLinks): this {
this.links = links
return this
}

/**
* Convert collection to plain object
*/
toArray(): any[] {
return this.items.map(item => {
if (item instanceof Resource) {
return item.toArray()
}
return item
})
}

/**
* Build full collection JSON response
*/
json(): { data: any[]; meta?: CollectionMeta; links?: CollectionLinks } {
return {
data: this.toArray(),
meta: Object.keys(this.meta).length ? this.meta : undefined,
links: Object.keys(this.links).length ? this.links : undefined,
}
}
}
Loading
Loading