{"id":16542525,"url":"https://github.com/tada5hi/rapiq","last_synced_at":"2025-07-05T09:36:12.099Z","repository":{"id":54349304,"uuid":"521277627","full_name":"tada5hi/rapiq","owner":"tada5hi","description":"A tiny library which provides utility types/functions for request and response query handling.","archived":false,"fork":false,"pushed_at":"2025-07-02T11:23:45.000Z","size":8265,"stargazers_count":19,"open_issues_count":6,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-02T12:29:52.184Z","etag":null,"topics":["api","api-utils","fields","include","json","json-api","pagination","query","relations","rest","sort","typescript"],"latest_commit_sha":null,"homepage":"https://rapiq.tada5hi.net","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tada5hi.png","metadata":{"files":{"readme":"README.MD","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["tada5hi"]}},"created_at":"2022-08-04T13:28:24.000Z","updated_at":"2025-07-02T11:23:28.000Z","dependencies_parsed_at":"2023-12-06T10:56:58.785Z","dependency_job_id":"98a0f0d1-8e07-4670-864a-32c7e3fd5a9c","html_url":"https://github.com/tada5hi/rapiq","commit_stats":{"total_commits":245,"total_committers":4,"mean_commits":61.25,"dds":0.4040816326530612,"last_synced_commit":"abff08900ac49b8c26f21e8dbe7553482606895c"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"purl":"pkg:github/tada5hi/rapiq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tada5hi%2Frapiq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tada5hi%2Frapiq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tada5hi%2Frapiq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tada5hi%2Frapiq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tada5hi","download_url":"https://codeload.github.com/tada5hi/rapiq/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tada5hi%2Frapiq/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263144210,"owners_count":23420649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-utils","fields","include","json","json-api","pagination","query","relations","rest","sort","typescript"],"created_at":"2024-10-11T18:57:49.397Z","updated_at":"2025-07-05T09:36:12.087Z","avatar_url":"https://github.com/tada5hi.png","language":"TypeScript","funding_links":["https://github.com/sponsors/tada5hi"],"categories":[],"sub_categories":[],"readme":"# rapiq 🌈\n\n[![npm version](https://badge.fury.io/js/rapiq.svg)](https://badge.fury.io/js/rapiq)\n[![main](https://github.com/Tada5hi/rapiq/actions/workflows/main.yml/badge.svg)](https://github.com/Tada5hi/rapiq/actions/workflows/main.yml)\n[![codecov](https://codecov.io/gh/tada5hi/rapiq/branch/master/graph/badge.svg?token=QFGCsHRUax)](https://codecov.io/gh/tada5hi/rapiq)\n[![Known Vulnerabilities](https://snyk.io/test/github/Tada5hi/rapiq/badge.svg)](https://snyk.io/test/github/Tada5hi/rapiq)\n[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)\n\n\u003e [!WARNING]\n\u003e This README includes the documentation for the upcoming version 2.\n\u003e\n\u003e This is the [link](https://github.com/tada5hi/rapiq/tree/v1) for the v1 (and prior).\n\nRapiq (**R**est **Api** **Q**uery) is a library to build an efficient interface between client- \u0026 server-side applications.\nIt defines a scheme for the request, but **not** for the response.\n\n**Table of Contents**\n\n- [Installation](#installation)\n- [Documentation](#documentation)\n- [Parameters](#parameters)\n- [Usage](#usage)\n- [License](#license)\n\n## Installation\n\n```bash\nnpm install rapiq --save\n```\n## Documentation\n\nTo read the docs, visit [https://rapiq.tada5hi.net](https://rapiq.tada5hi.net)\n\n## Parameters\n\n- `fields`\n    - Description: Return only specific resource fields or extend the default selection.\n    - URL-Parameter: **fields**\n- `filters`\n    - Description: Filter the resources, according to specific criteria.\n    - URL-Parameter: **filter**\n- `relations`\n    - Description: Include related resources of the primary resource.\n    - URL-Parameter: **include**\n- `pagination`\n    - Description: Limit the number of resources returned from the entire collection.\n    - URL-Parameter: **page**\n- `sort`\n    - Description: Sort the resources according to one or more keys in asc/desc direction.\n    - URL-Parameter: **sort**\n\nIt is based on the [JSON-API](https://jsonapi.org/format/) specification.\n\n## Usage\n\nThis is a small outlook on how to use the library. For detailed explanations and extended examples,\nread the [docs](https://rapiq.tada5hi.net).\n\n### Build 🔧\n\nThe first step is to construct a [BuildInput](https://rapiq.tada5hi.net/guide/build-api-reference#buildinput) object for a generic Record `\u003cT\u003e`.\nPass the object to the [buildQuery](https://rapiq.tada5hi.net/guide/build-api-reference#buildquery) method to convert it to a transportable string.\n\nThe `BuildInput\u003cT\u003e` can contain a configuration for each\n[Parameter](https://rapiq.tada5hi.net/guide/parameter-api-reference.md#parameter)/\n[URLParameter](https://rapiq.tada5hi.net/guide/parameter-api-reference.md#urlparameter).\n- [Fields](https://rapiq.tada5hi.net/guide/fields-api-reference.md#fieldsbuildinput): `FieldsBuildInput\u003cT\u003e`\n- [Filter(s)](https://rapiq.tada5hi.net/guide/filters-api-reference.md#filtersbuildinput): `FiltersBuildInput\u003cT\u003e`\n- [Pagination](https://rapiq.tada5hi.net/guide/pagination-api-reference.md#paginationbuildinput): `PaginationBuildInput\u003cT\u003e`\n- [Relations](https://rapiq.tada5hi.net/guide/relations-api-reference.md#relationsbuildinput): `RelationsBuildInput\u003cT\u003e`\n- [Sort](https://rapiq.tada5hi.net/guide/sort-api-reference.md#sortbuildinput): `SortBuildInput\u003cT\u003e`\n\n\u003e [!NOTE]\n\u003e Check out the API-Reference of each parameter for acceptable input formats and examples.\n\nAfter building, the string can be passed to a backend application as http query string argument.\nThe backend application can process the request, by [parsing](https://rapiq.tada5hi.net/guide/parse.md) the query string.\n\n#### Example\n\nThe following example is based on the assumption, that the following packages are installed:\n- [express](https://www.npmjs.com/package/express)\n- [typeorm](https://www.npmjs.com/package/typeorm)\n- [typeorm-extension](https://www.npmjs.com/package/typeorm-extension)\n\nIt should give an insight on how to use this library.\nTherefore, a type which will represent a `User` and a method `getAPIUsers` are defined.\nThe method should perform a request to the resource API to receive a collection of entities.\n\n```typescript\nimport axios from \"axios\";\nimport { Builder } from 'rapiq';\n\nexport type Realm = {\n    id: string,\n    name: string,\n    description: string,\n}\n\nexport type Item = {\n    id: string,\n    realm: Realm,\n    user: User\n}\n\nexport type User = {\n    id: number,\n    name: string,\n    email: string,\n    age: number,\n    realm: Realm,\n    items: Item[]\n}\n\ntype ResponsePayload = {\n    data: User[],\n    meta: {\n        limit: number,\n        offset: number,\n        total: number\n    }\n}\n\nconst builder = new Builder\u003cUser\u003e();\nbuilder.add({\n    pagination: {\n        limit: 20,\n        offset: 10\n    },\n    filters: {\n        id: 1\n    },\n    fields: ['id', 'name'],\n    sort: '-id',\n    relations: ['realm']\n});\n\n// console.log(builder.toString());\n// ?filter[id]=1\u0026fields=id,name\u0026page[limit]=20\u0026page[offset]=10\u0026sort=-id\u0026include=realm\n\nasync function getAPIUsers(\n    builder: Builder\u003cUser\u003e\n): Promise\u003cResponsePayload\u003e {\n    const response = await axios.get(`users${builder.toString()}`);\n\n    return response.data;\n}\n\n(async () =\u003e {\n    let response = await getAPIUsers(builder);\n\n    // do something with the response :)\n})();\n```\n\nThe next [section](#parse-) will describe, how to parse the query string on the backend side.\n\n### Parse 🔎\n\nThe last step of the whole process is to parse the transpiled query string, to an efficient data structure.\nThe result object (`ParseOutput`) can contain an output for each\n[Parameter](https://rapiq.tada5hi.net/guide/parameter-api-reference.md#parameter)/\n[URLParameter](https://rapiq.tada5hi.net/guide/parameter-api-reference.md#urlparameter).\n- [Fields](https://rapiq.tada5hi.net/guide/fields-api-reference.md#fieldsparseoutput): `FieldsParseOutput\u003cT\u003e`\n- [Filter(s)](https://rapiq.tada5hi.net/guide/filters-api-reference.md#filtersparseoutput): `FiltersParseOutput\u003cT\u003e`\n- [Pagination](https://rapiq.tada5hi.net/guide/pagination-api-reference.md#paginationparseoutput): `PaginationParseOutput\u003cT\u003e`\n- [Relations](https://rapiq.tada5hi.net/guide/relations-api-reference.md#relationsparseoutput): `RelationsParseOutput\u003cT\u003e`\n- [Sort](https://rapiq.tada5hi.net/guide/sort-api-reference.md#sortparseoutput): `SortParseOutput\u003cT\u003e`\n\n\u003e **NOTE**: Check out the API-Reference of each parameter for output formats and examples.\n\n#### Example\n\nThe following example is based on the assumption, that the following packages are installed:\n- [express](https://www.npmjs.com/package/express)\n- [typeorm](https://www.npmjs.com/package/typeorm)\n- [typeorm-extension](https://www.npmjs.com/package/typeorm-extension)\n\nFor explanation purposes, three simple entities with relations between them are declared to demonstrate\nthe usage on the backend side.\n\n**`entities.ts`**\n```typescript\nimport {\n    Entity,\n    PrimaryGeneratedColumn,\n    Column,\n    OneToMany,\n    JoinColumn,\n    ManyToOne\n} from \"typeorm\";\n\n@Entity()\nexport class User {\n    @PrimaryGeneratedColumn({unsigned: true})\n    id: number;\n\n    @Column({type: 'varchar', length: 30})\n    @Index({unique: true})\n    name: string;\n\n    @Column({type: 'varchar', length: 255, default: null, nullable: true})\n    email: string;\n\n    @Column({type: 'int', nullable: true})\n    age: number\n\n    @ManyToOne(() =\u003e Realm, { onDelete: 'CASCADE' })\n    realm: Realm;\n\n    @OneToMany(() =\u003e User, { onDelete: 'CASCADE' })\n    items: Item[];\n}\n\n@Entity()\nexport class Realm {\n    @PrimaryColumn({ type: 'varchar', length: 36 })\n    id: string;\n\n    @Column({ type: 'varchar', length: 128, unique: true })\n    name: string;\n\n    @Column({ type: 'text', nullable: true, default: null })\n    description: string | null;\n}\n\n@Entity()\nexport class Item {\n    @PrimaryGeneratedColumn({unsigned: true})\n    id: number;\n\n    @ManyToOne(() =\u003e Realm, { onDelete: 'CASCADE' })\n    realm: Realm;\n\n    @ManyToOne(() =\u003e User, { onDelete: 'CASCADE' })\n    user: User;\n}\n```\n\n```typescript\nimport { Request, Response } from 'express';\n\nimport {\n    applyQuery,\n    useDataSource\n} from 'typeorm-extension';\n\n/**\n * Get many users.\n *\n * Request example\n * - url: /users?page[limit]=10\u0026page[offset]=0\u0026include=realm\u0026filter[id]=1\u0026fields=id,name\n *\n * @param req\n * @param res\n */\nexport async function getUsers(req: Request, res: Response) {\n    const dataSource = await useDataSource();\n    const repository = dataSource.getRepository(User);\n    const query = repository.createQueryBuilder('user');\n\n    // -----------------------------------------------------\n\n    // parse and apply data on the db query.\n    const { pagination } = applyQuery(query, req.query, {\n        defaultPath: 'user',\n        fields: {\n            allowed: ['id', 'name', 'realm.id', 'realm.name'],\n        },\n        filters: {\n            allowed: ['id', 'name', 'realm.id'],\n        },\n        relations: {\n            allowed: ['items', 'realm']\n        },\n        pagination: {\n            maxLimit: 20\n        },\n        sort: {\n            allowed: ['id', 'name', 'realm.id'],\n        }\n    });\n\n    // -----------------------------------------------------\n\n    const [entities, total] = await query.getManyAndCount();\n\n    return res.json({\n        data: {\n            data: entities,\n            meta: {\n                total,\n                ...pagination\n            }\n        }\n    });\n}\n```\n\n## License\n\nMade with 💚\n\nPublished under [MIT License](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftada5hi%2Frapiq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftada5hi%2Frapiq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftada5hi%2Frapiq/lists"}