Skip to content

Commit aab250d

Browse files
authored
Merge pull request #9 from ismailza/docs/add-docs-website
docs: add the documentation website
2 parents d3cfa7b + 82fab0b commit aab250d

38 files changed

Lines changed: 24180 additions & 30 deletions

.github/workflows/docs.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Docs
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "website/**"
9+
- ".github/workflows/docs.yml"
10+
pull_request:
11+
branches:
12+
- main
13+
paths:
14+
- "website/**"
15+
- ".github/workflows/docs.yml"
16+
workflow_dispatch:
17+
18+
# Allow one concurrent deployment, and let a new push cancel a running build.
19+
concurrency:
20+
group: ${{ github.workflow }}-${{ github.ref }}
21+
cancel-in-progress: true
22+
23+
jobs:
24+
build:
25+
runs-on: ubuntu-latest
26+
27+
defaults:
28+
run:
29+
working-directory: website
30+
31+
steps:
32+
- uses: actions/checkout@v5
33+
34+
- uses: actions/setup-node@v5
35+
with:
36+
node-version: 22
37+
cache: npm
38+
cache-dependency-path: website/package-lock.json
39+
40+
- run: npm ci
41+
42+
- name: Type check
43+
run: npm run typecheck
44+
45+
# Fails on broken internal links.
46+
- name: Build
47+
run: npm run build
48+
49+
- name: Upload Pages artifact
50+
if: github.event_name != 'pull_request'
51+
uses: actions/upload-pages-artifact@v5
52+
with:
53+
path: website/build
54+
55+
deploy:
56+
needs: build
57+
if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
58+
59+
runs-on: ubuntu-latest
60+
61+
permissions:
62+
pages: write
63+
id-token: write
64+
65+
environment:
66+
name: github-pages
67+
url: ${{ steps.deployment.outputs.page_url }}
68+
69+
steps:
70+
- name: Deploy to GitHub Pages
71+
id: deployment
72+
uses: actions/deploy-pages@v5

README.md

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
1-
# ngx-api-client
2-
3-
[![npm](https://img.shields.io/npm/v/@ismailza/ngx-api-client.svg)](https://www.npmjs.com/package/@ismailza/ngx-api-client)
4-
[![CI](https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml/badge.svg)](https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml)
5-
[![Release](https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml/badge.svg)](https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml)
6-
[![license](https://img.shields.io/npm/l/@ismailza/ngx-api-client.svg)](./LICENSE)
7-
8-
A typed, interceptor-driven HTTP layer for Angular.
1+
<p align="center">
2+
<a href="https://ismailza.github.io/ngx-api-client/">
3+
<img src="https://ismailza.github.io/ngx-api-client/img/logo.svg" alt="" width="88" height="88">
4+
</a>
5+
</p>
6+
7+
<h1 align="center">ngx-api-client</h1>
8+
9+
<p align="center">
10+
A typed, interceptor-driven HTTP layer for Angular.
11+
</p>
12+
13+
<p align="center">
14+
<a href="https://ismailza.github.io/ngx-api-client/"><strong>Documentation</strong></a> ·
15+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><strong>npm</strong></a> ·
16+
<a href="https://ismailza.github.io/ngx-api-client/docs/getting-started/quick-start"><strong>Quick start</strong></a> ·
17+
<a href="https://ismailza.github.io/ngx-api-client/docs/api/provide-api"><strong>API reference</strong></a>
18+
</p>
19+
20+
<p align="center">
21+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><img src="https://img.shields.io/npm/v/@ismailza/ngx-api-client.svg" alt="npm version"></a>
22+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><img src="https://img.shields.io/npm/dm/@ismailza/ngx-api-client.svg" alt="npm downloads"></a>
23+
<a href="https://ismailza.github.io/ngx-api-client/"><img src="https://img.shields.io/badge/docs-online-brightgreen.svg" alt="Documentation"></a>
24+
<a href="https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml"><img src="https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
25+
<a href="https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml"><img src="https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml/badge.svg" alt="Release"></a>
26+
<a href="./LICENSE"><img src="https://img.shields.io/npm/l/@ismailza/ngx-api-client.svg" alt="License"></a>
27+
</p>
928

1029
`HttpClient` gives you a request. It doesn't give you a _policy_ — where the base
1130
URL comes from, how a failed response becomes something your components can
@@ -48,17 +67,23 @@ export const appConfig: ApplicationConfig = {
4867
retry: { maxRetries: 3, initialDelay: 1000 },
4968
}),
5069
provideHttpClient(
51-
withInterceptors([retryInterceptor, apiErrorInterceptor, apiSuccessInterceptor]),
70+
withInterceptors([apiErrorInterceptor, apiSuccessInterceptor, retryInterceptor]),
5271
),
5372
],
5473
};
5574
```
5675

5776
Interceptors are registered by you, not by `provideApi()`, because **order
58-
matters** and only you know what else is in the chain. Put an auth/bearer-token
59-
interceptor first so retried requests get a fresh token; keep `retryInterceptor`
60-
before `apiErrorInterceptor` so the error handler only sees failures that
61-
survived every retry.
77+
matters** and only you know what else is in the chain. The first interceptor in
78+
the array is the outermost one:
79+
80+
- Keep `apiErrorInterceptor` **before** `retryInterceptor`. It replaces the
81+
`HttpErrorResponse` with a plain `ApiError`, and `retryInterceptor` only
82+
retries `HttpErrorResponse`s — nest them the other way round and retry
83+
silently never fires. Outermost, it also reports one failure per operation
84+
rather than one per attempt.
85+
- Put an auth/bearer-token interceptor **last**, inside `retryInterceptor`, so
86+
each retried attempt is signed with a fresh token.
6287

6388
## Usage
6489

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import tseslint from 'typescript-eslint';
55

66
export default tseslint.config(
77
{
8-
ignores: ['dist/**', 'coverage/**', '.angular/**', 'node_modules/**'],
8+
ignores: ['dist/**', 'coverage/**', '.angular/**', 'node_modules/**', 'website/**'],
99
},
1010
{
1111
files: ['**/*.ts'],

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
"watch": "ng build --watch --configuration development",
99
"test": "ng test",
1010
"lint": "eslint .",
11-
"lint:fix": "eslint . --fix"
11+
"lint:fix": "eslint . --fix",
12+
"docs:install": "npm --prefix website ci",
13+
"docs:start": "npm --prefix website start",
14+
"docs:build": "npm --prefix website run build",
15+
"docs:serve": "npm --prefix website run serve"
1216
},
1317
"private": true,
1418
"packageManager": "npm@11.9.0",

projects/ngx-api-client/README.md

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
1-
# ngx-api-client
2-
3-
A typed, interceptor-driven HTTP layer for Angular.
1+
<p align="center">
2+
<a href="https://ismailza.github.io/ngx-api-client/">
3+
<img src="https://ismailza.github.io/ngx-api-client/img/logo.svg" alt="" width="88" height="88">
4+
</a>
5+
</p>
6+
7+
<h1 align="center">ngx-api-client</h1>
8+
9+
<p align="center">
10+
A typed, interceptor-driven HTTP layer for Angular.
11+
</p>
12+
13+
<p align="center">
14+
<a href="https://ismailza.github.io/ngx-api-client/"><strong>Documentation</strong></a> ·
15+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><strong>npm</strong></a> ·
16+
<a href="https://ismailza.github.io/ngx-api-client/docs/getting-started/quick-start"><strong>Quick start</strong></a> ·
17+
<a href="https://ismailza.github.io/ngx-api-client/docs/api/provide-api"><strong>API reference</strong></a>
18+
</p>
19+
20+
<p align="center">
21+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><img src="https://img.shields.io/npm/v/@ismailza/ngx-api-client.svg" alt="npm version"></a>
22+
<a href="https://www.npmjs.com/package/@ismailza/ngx-api-client"><img src="https://img.shields.io/npm/dm/@ismailza/ngx-api-client.svg" alt="npm downloads"></a>
23+
<a href="https://ismailza.github.io/ngx-api-client/"><img src="https://img.shields.io/badge/docs-online-brightgreen.svg" alt="Documentation"></a>
24+
<a href="https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml"><img src="https://github.com/ismailza/ngx-api-client/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
25+
<a href="https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml"><img src="https://github.com/ismailza/ngx-api-client/actions/workflows/release.yml/badge.svg" alt="Release"></a>
26+
<a href="./LICENSE"><img src="https://img.shields.io/npm/l/@ismailza/ngx-api-client.svg" alt="License"></a>
27+
</p>
428

529
`HttpClient` gives you a request. It doesn't give you a _policy_ — where the base
630
URL comes from, how a failed response becomes something your components can
@@ -43,17 +67,23 @@ export const appConfig: ApplicationConfig = {
4367
retry: { maxRetries: 3, initialDelay: 1000 },
4468
}),
4569
provideHttpClient(
46-
withInterceptors([retryInterceptor, apiErrorInterceptor, apiSuccessInterceptor]),
70+
withInterceptors([apiErrorInterceptor, apiSuccessInterceptor, retryInterceptor]),
4771
),
4872
],
4973
};
5074
```
5175

5276
Interceptors are registered by you, not by `provideApi()`, because **order
53-
matters** and only you know what else is in the chain. Put an auth/bearer-token
54-
interceptor first so retried requests get a fresh token; keep `retryInterceptor`
55-
before `apiErrorInterceptor` so the error handler only sees failures that
56-
survived every retry.
77+
matters** and only you know what else is in the chain. The first interceptor in
78+
the array is the outermost one:
79+
80+
- Keep `apiErrorInterceptor` **before** `retryInterceptor`. It replaces the
81+
`HttpErrorResponse` with a plain `ApiError`, and `retryInterceptor` only
82+
retries `HttpErrorResponse`s — nest them the other way round and retry
83+
silently never fires. Outermost, it also reports one failure per operation
84+
rather than one per attempt.
85+
- Put an auth/bearer-token interceptor **last**, inside `retryInterceptor`, so
86+
each retried attempt is signed with a fresh token.
5787

5888
## Usage
5989

@@ -257,14 +287,16 @@ matrix currently covers.
257287

258288
## Contributing
259289

260-
```bash
261-
npm install
262-
npm test # 131 specs, vitest
263-
npm run build
264-
```
290+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) before opening an issue or pull request.
265291

266-
Issues and pull requests are welcome.
292+
## Code of Conduct
293+
294+
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) to help us maintain a welcoming and inclusive community.
267295

268296
## License
269297

270-
[MIT](../../LICENSE) © Ismail ZAHIR
298+
[MIT](./LICENSE) © Ismail ZAHIR
299+
300+
## Support the Project
301+
302+
If you find this library useful, consider giving it a ⭐ on GitHub. It helps others discover the project and motivates future development.

website/.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Dependencies
2+
/node_modules
3+
4+
# Production
5+
/build
6+
7+
# Generated files
8+
.docusaurus
9+
.cache-loader
10+
11+
# Misc
12+
.DS_Store
13+
.env.local
14+
.env.development.local
15+
.env.test.local
16+
.env.production.local
17+
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*

website/README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Documentation website
2+
3+
The documentation site for [`@ismailza/ngx-api-client`](https://www.npmjs.com/package/@ismailza/ngx-api-client),
4+
built with [Docusaurus](https://docusaurus.io/).
5+
6+
Published at **https://ismailza.github.io/ngx-api-client/**.
7+
8+
## Local development
9+
10+
From the repository root:
11+
12+
```bash
13+
npm run docs:start
14+
```
15+
16+
…or from this directory:
17+
18+
```bash
19+
npm install
20+
npm run start
21+
```
22+
23+
Most changes are reflected live without restarting the server.
24+
25+
## Build
26+
27+
```bash
28+
npm run build # static output in ./build
29+
npm run serve # serve the production build locally
30+
npm run typecheck # type-check the site source
31+
```
32+
33+
`npm run build` fails on broken internal links, so it is the check to run before
34+
opening a documentation pull request.
35+
36+
## Structure
37+
38+
```
39+
docs/
40+
intro.md What the library is and what it deliberately isn't
41+
getting-started/ Installation and quick start
42+
guides/ One page per concern (configuration, versioning, retry, …)
43+
api/ Reference for the public API surface
44+
src/
45+
pages/index.tsx Landing page
46+
components/ Landing page sections
47+
css/custom.css Theme tokens
48+
sidebars.ts Explicit sidebar — new pages must be added here
49+
docusaurus.config.ts Site config, navbar, footer, deployment URL
50+
```
51+
52+
The sidebar is defined explicitly rather than autogenerated, so **a new page is
53+
invisible until it is listed in `sidebars.ts`**.
54+
55+
## Writing conventions
56+
57+
- Document what the code does, not what it might do — check the source in
58+
`projects/ngx-api-client/src/lib` before stating a default.
59+
- Every option table gives the type, the default, and whether it can be
60+
overridden per request.
61+
- Code samples are complete enough to paste into an application.
62+
63+
## Deployment
64+
65+
`.github/workflows/docs.yml` builds the site on every pull request that touches
66+
`website/`, and deploys to GitHub Pages on push to `main`. No manual `npm run
67+
deploy` is needed.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
id: api-loading-service
3+
title: ApiLoadingService
4+
description: API reference for ApiLoadingService, the signal-based in-flight request counter.
5+
---
6+
7+
# `ApiLoadingService`
8+
9+
```ts
10+
@Injectable({ providedIn: 'root' })
11+
class ApiLoadingService {
12+
readonly loading: Signal<boolean>;
13+
}
14+
```
15+
16+
Tracks the number of in-flight API requests and exposes a reactive signal.
17+
18+
## `loading`
19+
20+
```ts
21+
readonly loading: Signal<boolean>;
22+
```
23+
24+
`true` while at least one tracked request is outstanding. It counts rather than
25+
flags, so two concurrent requests don't switch the indicator off when the first
26+
one finishes.
27+
28+
```ts
29+
@Component({
30+
template: `@if (loading.loading()) {
31+
<my-progress-bar />
32+
}`,
33+
})
34+
export class AppShell {
35+
protected readonly loading = inject(ApiLoadingService);
36+
}
37+
```
38+
39+
## Behaviour
40+
41+
- The counter is incremented on **subscribe** and released on completion, error
42+
or unsubscribe — a component destroyed mid-request never strands it.
43+
- It moves **once per `ApiService` call**, not once per HTTP attempt, so a
44+
retried request holds the indicator for the whole operation.
45+
- An observable you never subscribe to never touches it.
46+
47+
`start()` and `stop()` are internal to `ApiService` and should not be called by
48+
application code.
49+
50+
## Excluding requests
51+
52+
```ts
53+
this.api.get<Notification[]>('/notifications', { showLoader: false });
54+
```
55+
56+
Or invert the default with `defaultShowLoader: false` in `provideApi()` and opt
57+
individual calls in with `showLoader: true`. See
58+
[Loading state](../guides/loading-state.mdx).

0 commit comments

Comments
 (0)