- Simple app for creating reports from Bakalari school system data
npm install bakalari-api-tsThis package also includes some helpers and services for easier integration
The bakalari-api-v3 project provided great insights into how the Bakalari (Mobile) API works
The project follows a structured pattern to organize the API client logic:
- Models (src/models):
- Dtos returned by the Bakalari API endpints, also special models for uses in services
- Resources (src/resources):
- Specific endpoints areas of the Bakalari API (e.g., /3/timetable - TimetableResource, /3/event/ - EventResource)
- Services (src/services):
- They contain the resource and can also provide additional logic on top
- BakalariClient (src/bakalari.client.ts):
- Main entry point consumer of this pacakge will use - contains all the services and authentication logic
``bash`
npm install bakalari-api-ts
An example of getting timetable for an account:
`ts
import { BakalariClient } from 'bakalari-api-ts';
import { DateTime } from 'luxon';
// Create the client for specific school
const client = new BakalariClient('YOUR_SCHOOL_API_URL', 'YOUR_USERNAME', 'YOUR_PASSWORD');
// Initialize (authenticate)
await client.authenticate();
// You can now acccess various services in the client, for example timetable service:
const summary = await client.timetable.getMonthTimetableSummary(
DateTime.now()
)
// You can also access the underlying resource of each service (to directly access the endpoints):
const rawTimetable = await client.timetable.resource.getWeekTimetable(
DateTime.now()
)
`
| Status | Method | Endpoint |
| :---- |:-------| :---- |
| ⏳ | GET | /api |
| ⏳ | GET | /api/3 |
| ⚠️ | GET | /api/3/absence/student |
| ✅ | GET | /api/3/classbook |
| ✅ | GET | /api/3/classbook/lessonTags |
| ✅ | GET | /api/3/events |
| ✅ | GET | /api/3/events/my |
| ✅ | GET | /api/3/events/public |
| ⚠️ | GET | /api/3/gdpr/commissioner |
| ⚠️ | POST | /api/3/gdpr/commissioner/send-objection |
| ⚠️ | POST | /api/3/gdpr/commissioner/send-report |
| ⚠️ | GET | /api/3/gdpr/commissioners |
| ⚠️ | GET | /api/3/gdpr/consent |
| ⚠️ | GET | /api/3/gdpr/consents/person |
| ⚠️ | GET | /api/3/gdpr/consents/person/child |
| ⚠️ | GET | /api/3/homeworks |
| ⚠️ | GET | /api/3/homeworks/count-actual |
| ⚠️ | GET | /api/3/komens/attachment/{id} |
| ⚠️ | POST | /api/3/komens/message |
| ⚠️ | GET | /api/3/komens/message/{id} |
| ⚠️ | PUT | /api/3/komens/message/{id}/mark-as-read |
| ✅️ | GET | /api/3/komens/message-types |
| ⚠️ | POST | /api/3/komens/message-types/edit |
| ⚠️ | POST | /api/3/komens/message-types/reply |
| ⚠️ | POST | /api/3/komens/messages/apology |
| ✅ | POST | /api/3/komens/messages/noticeboard |
| ✅️ | GET | /api/3/komens/messages/noticeboard/unread |
| ⚠️ | GET | /api/3/komens/messages/rating |
| ✅ | POST | /api/3/komens/messages/received |
| ⚠️ | GET | /api/3/komens/messages/received/{id} |
| ⚠️ | GET | /api/3/komens/messages/sent/{id} |
| ✅️ | GET | /api/3/komens/messages/received/unread |
| ✅ | POST | /api/3/komens/messages/sent |
| ⚠️ | GET | /api/3/komens/rating-templates |
| ⏳ | GET | /api/3/lesson/... |
| ✅ | POST | /api/3/login |
| ✅ | GET | /api/3/logintoken |
| ✅ | GET | /api/3/marking/atoms |
| ✅ | GET | /api/3/marking/marks/{id} |
| ⚠️ | GET | /api/3/marks |
| ⚠️ | GET | /api/3/marks/count-new |
| ⚠️ | GET | /api/3/marks/final |
| ⚠️ | GET | /api/3/marks/measures |
| ⚠️ | GET | /api/3/marks/what-if |
| ⚠️ | GET | /api/3/payments/classfund |
| ⚠️ | GET | /api/3/payments/classfund/paymentsinfo |
| ⚠️ | GET | /api/3/payments/classfund/summary |
| ⚠️ | POST | /api/3/register-notification |
| ⚠️ | GET | /api/3/subjects |
| ⚠️ | GET | /api/3/subjects/themes/{id} |
| ✅ | GET | /api/3/substitutions |
| ✅ | GET | /api/3/timetable/actual |
| ✅ | GET | /api/3/timetable/permanent |
| ⏳ | GET | /Timetable/Public/ |
| ⚠️ | DELETE | /api/3/unregister-user-notification |
| ✅ | GET | /api/3/user |
| ✅ | GET | /api/3/webmodule |
Explains how to add support for new endpoints to the bakalari-api-ts client
To add a new set of endpoints, you'll need to create or modify the following files:
- src/models/: Define models for the data returned by the new endpointssrc/resources/
- : Create a new resource file for the new endpointssrc/services/
- : Create a new service file that uses the new resourcesrc/bakalari.client.ts
- : Update the main client to include the new service
Let's walk through an example of adding the api/3/gdpr endpoints.
#### Step 1: Create the Resource
First, create a new resource file at src/resources/gdpr.resource.ts
This file will contain a class with methods that make the actual API calls (basically a repository)
(Note - in the example, the endpoints start with the /3/ prefix - this is because the base API address should already contain the /api/ part)
`typescript
// src/resources/gdpr.resource.ts
import type { Api } from '../api/base.api';
import { objectToCamel } from 'ts-case-convert';
export class GdprResource {
private readonly api: Api;
constructor(api: Api) {
this.api = api;
}
// GET /3/gdpr/commissioner
async getCommissioner(): Promise
const response = await this.api.client.get('/3/gdpr/commissioner');
return objectToCamel(response.data);
}
// POST /3/gdpr/commissioner/send-objection
async sendObjection(data: any): Promise
const response = await this.api.client.post('/3/gdpr/commissioner/send-objection', data);
return objectToCamel(response.data);
}
// And so on for the other GDPR endpoints...
}
`
#### Step 2: Create the Service
Next, create a new service file at src/services/gdpr.service.ts
The service can provide additional logic if needed
It exposes the resource, so the consumer can access the resource through it
`typescript
// src/services/gdpr.service.ts
import { GdprResource } from '../resources/gdpr.resource';
import { Api } from '../api/base.api';
export class GdprService {
public readonly resource: GdprResource;
constructor(api: Api) {
this.resource = new GdprResource(api);
}
async getCommissioner(): Promise
return this.resource.getCommissioner();
}
async sendObjection(data: any): Promise
return this.resource.sendObjection(data);
}
// And so on...
}
`
#### Step 3: Update the BakalariClient
Finally, add the new GdprService to the BakalariClient in src/bakalari.client.ts
`typescript
// src/bakalari.client.ts
import { TimetableService } from './services/timetable.service';
import { Api } from './api/base.api';
import type { Credentials } from './models/credentials.model';
import { LoginService } from './services/login.service';
import { AbsenceService } from './services/absence.service';
import { ClassbookService } from './services/classbook.service';
import { EventService } from './services/event.service';
import { GdprService } from './services/gdpr.service'; // 1. Import the new service
export class BakalariClient {
private readonly login: LoginService;
public readonly timetable: TimetableService;
public readonly absence: AbsenceService;
public readonly classbook: ClassbookService;
public readonly event: EventService;
public readonly gdpr: GdprService; // 2. Add the service as a public property
constructor(baseUrl: string, credentials: Credentials) {
const api = new Api(baseUrl);
this.login = new LoginService(api, credentials);
this.timetable = new TimetableService(api);
this.absence = new AbsenceService(api);
this.classbook = new ClassbookService(api);
this.event = new EventService(api);
this.gdpr = new GdprService(api); // 3. Instantiate the new service
}
async authenticate() {
await this.login.authenticate();
}
}
`
It's a good practice to create models for the data returned by the API
For example, if the /3/gdpr/commissioner endpoint returns a commissioner object, you could create a commissioner.model.ts file in src/models:
`typescript`
// src/models/commissioner.model.ts
export interface Commissioner {
id: string;
name: string;
// ... other properties
}
You can then use this model in your resource and service files to provide strong typing
`typescript
// src/resources/gdpr.resource.ts
import { Commissioner } from '../models/commissioner.model';
import { objectToCamel } from 'ts-case-convert';
export class GdprResource {
// ...
async getCommissioner(): Promise
const response = await this.api.client.get('/3/gdpr/commissioner');
return objectToCamel
}
// ...
}
`
Also, to also test the functionality of the new endpoints, you can create test files in the e2e (end to end tests) or tests (unit tests) foldere2e/bakalari.client.e2e.test.ts: Test for the new resource - define new describe
for example, creating e2e tests for the GDPR endpoints:
`typescript
// ...
describe('BakalariClient.gdpr.resource', () => {
test('getClassbooks', async () => {
//
// Arrange
//
// eslint-disable-next-line no-undef
const client = new BakalariClient(process.env.APP_BAKALARI_URL!, { username: process.env.APP_USERNAME!, password: process.env.APP_PASSWORD! });
//
// Act
//
await client.authenticate();
const result = await client.classbook.resource.getCommissioner();
//
// Assert
//
console.log(JSON.stringify(result, null, 2));
expect(result).toBeDefined();
});
});
// ...
``