Documentation and API are in WiP stage
Some endpoints require authentication.
To authenticate, first generate a token using the POST /api/v1/auth/login endpoint.
Then pass the received token via the Authorization header as a Bearer token. (Authorization: Bearer <token>)
The following controllers were implemented manually and contain custom endpoints that might function differently to autogenerated controllers.
- GET /api/v1/files/:key
- Returns metadata for a given file
- Response: serialized
FileEntryinstnace
- POST /api/v1/files
- Requres authentication
- Uploads a new file to the server
- Requires a multipart request body
- File must be uploaded in a field called
file
- File must be uploaded in a field called
- Response:
{ "key": "<full key of the uploaded file>" }
- GET /api/v1/about_us
- Returns "about us" data
- Response:
{ "data": { "aboutUs": AboutUsGeneral, "solvroSocialLinks": AboutUsGeneralLink[] } }- the AboutUsGeneral object has the
coverPhotorelation automatically included
- the AboutUsGeneral object has the
- POST /api/v1/auth/login
- Requires a json request body:
{ "email": string, "password": string, "rememberMe"?: boolean }- technically you can also pass these with query parameters, but please don't
- Creates and returns a new token for the specified user, if the credentials are correct
- the token is valid for 30 days if
rememberMe= true, 1 day otherwise.
- the token is valid for 30 days if
- Response:
{ "user": User, "token": "<token string>" }
- Requires a json request body:
- GET /api/v1/auth/me
- Requires authentication
- Returns your user object
- Response: serialized
Userinstance
- POST /api/v1/auth/logout
- Requires authentication
- Invalidates the current token
- Response:
{ "success": true, "message": "Logged out" }
- GET /api/v1/newsfeed/latest
- Returns the first page of university news items
- Accepts optional query parameters:
completeOnly- boolean, defaults totrue, only includes fully scraped news items (with no missing fields)lang- enum:pl,en; defaults topl, selects the newsfeed's language, languages contain different news items
- Response:
{ "articles": { "url": string, "imageLink": string, "title": string, "previewText": string, "date": string, "categories": string[] }[], "updateTime": string }
- GET /api/v1/newsfeed/stats
- Returns stats about the scraped news items
- includes count of articles scraped and the last update timestamp
- Response:
Partial<Record<NewsfeedLanguage, { "completeCount": number, "totalCount": number, "lastUpdate": string }>>
- Returns stats about the scraped news items
Most other models get an autogenerated controller with multiple standard endpoints.
All names in paths are in snake_case.
- GET /api/v1/:model
- Lists all available objects of a requested type
- Supports pagination, on-demand recursive relations, filtering and sorting (see below)
- Response:
{ "meta": <pagination data, if paginated>, "data": Model[] }
- GET /api/v1/:model/:id
- Returns the requested object
- Supports on-demand recursive relations
- Response:
{ "data": Model }
- POST /api/v1/:model
- Requres authentication
- Creates the requested object
- Requires a json request body with the object to create (full model)
- Response:
{ "success": true, "data": Model }
- PATCH /api/v1/:model/:id
- Requres authentication
- Updates the requested object
- Requires a json request body with the changes to apply (partial model)
- Response:
{ "success": true, "data": Model }
- DELETE /api/v1/:model/:id
- Requres authentication
- Deletes the requested object
- Response:
{ "success": true }
- GET /api/v1/:model/:id/:crudRelation
- Lists all objects associated with the requested object (
id) via the specified relation (crudRelation) - Supports pagination, on-demand recursive relations (relative to the requested relation), filtering and sorting
- Response:
{ "meta": <pagination data, if paginated>, "data": RelatedModel[] }
- Lists all objects associated with the requested object (
- POST /api/v1/:model/:id/:crudRelation
- Requires authentication
- Only applies to 1:n relations (hasMany)
- Creates a new object (from json body) associated with the requested object (
id) via the specified relation (crudRelation) - Requires a json request body with the object to create (full model, -fk)
- Response:
{ "success": true, "data": RelatedModel }
- POST /api/v1/:model/:mainId/:crudRelation/:relatedId
- Requires authentication
- Only applies to n:m relations (manyToMany)
- Attaches an existing object (
relatedId) to the requested object (mainId) via the specified relation (crudRelation) - Requires a json request body with any non-autoGenerated pivot fields.
- Response:
{ "success": true }
- DELETE /api/v1/:model/:mainId/:crudRelation/:relatedId
- Requires authentication
- Only applies to n:m relations (manyToMany)
- Removes the relation (
crudRelation) between the related object (relatedId) and the requested object (mainId) - If the related object is attached multiple times, all attachments are removed by default
- Pivot properties marked as
detachFilter: truecan be specified via query params or json body as filters to limit which attachments are removed
- Pivot properties marked as
- Response:
{ "success": true, "numDetached": <number> }
To find out what properties are allowed for each model in json bodies, see the respective model definition files. (in /app/models)
All endpoints that require a model in the json body recognize all column fields that aren't considered autoGenerated.
A field is considered autoGenerated if:
- it is explicitly marked as
autoGenerated: true, or - it is makred as
isPrimary: true,autoCreate: trueorautoUpdate: true, and is NOT marked asautoGenerated: false.
Additionally, endpoints marked with -fk ignore the corresponding foreign key of the requested relation.
This field will be automatically set to the primary key of the main object. (mainId)
Endpoints marked with full model require that you send ALL recognized column fields that aren't marked with optional: true.
Endpoints marked with partial model consider all fields to be optional.
To find out which relations are valid for each controller, see that controller's definition file. (in /app/controllers)
For on-demand recursive relations, look at the queryRelations array.
For relations specified as a path variable, look at the crudRelations array.
All autogenerated enpoints are not paginated by default - pagination must be explicitly requested.
To request pagination on a supported endpoint, set the page query parameter to a positive integer.
By default, a page size of 10 is used. Set the limit query parameter to set a custom page size.
When pagination is requested, pagination metadata will be returned in the meta field.
This field will include information such as:
total- the total record countlastPage- the total number of pages
For example, to request the 5th page of buildings, with 15 buildings per page:
GET https://api.topwr.solvro.pl/api/v1/buildings?page=5&limit=15
Some autogenerated endpoints support on-demand recursive relations. These allow you to fetch related objects along with the main object, in a single API request.
To request a relation, set its name to true in the query parameters.
Recursive relation chains contain . in their names.
If you request a relation chain, any relations along the way will be requested and returned as well.
Arrays of related objects will be attached to a property with the relation's name.
Example:
- Request:
GET https://api.topwr.solvro.pl/api/v1/campuses/1?buildings.aeds=true - Response:
{ "id": 1, ...campus properties..., "buildings": [ { "id": ..., "campusId": 1, ...building properties..., "aeds": [ { "id": ..., "buildingId": 1, ...aed properties... } ] }, ...more buildings... ] }
To request the response to be sorted by a specified key, add a sort query parameter.
To sort in ascending order, use +<column_name>.
To sort in descending order, use -<column_name>.
For example, to sort campuses by name, in ascending order, send the following request:
GET https://api.topwr.solvro.pl/api/v1/campuses?sort=+name
To request filtering, pass property names & predicates as query parameter keys and values. Property names should use the same casing as in model definition files. (camelCase)
For strings properties, the values are matched against the predicates using ILIKE - this means the filtering is case insensitive, and % can be used as a wildcard.
Other types of properties are matched using direct equality.
Examples:
- get all fields of study that belong to department number six:
GET https://api.topwr.solvro.pl/api/v1/fields_of_study?departmentId=6 - get all contributors' youtube links:
GET https://api.topwr.solvro.pl/api/v1/contributor_social_links?linkType=youtu - get all campuses whose names end with
a:
GET https://api.topwr.solro.pl/api/v1/campuses?name=%a
Any numeric or date-time field can be filtered by range. Pass the following query params to filter by range:
- for lower bound of greater or equal to value:
<param>.from=<value> - for upper bound of lesser or equal to value:
<param>.to=<value> - for both lower and upper bound, pass both params separately (that is:
<param>.from=<value>&<param>.to=<value>)
You can pass both from lower bound and to upper bound or only one of them.
If from is equal to to, the filter works exactly like the single value filter (in other words: departmentId.from=1&departmentId.to=1 is equal to departmentId=1).
Example of a correctly formed request:
Goal: Fields of study belonging to departments with ids ranging from two to four, both ends inclusive
Request: GET https://api.topwr.solvro.pl/api/v1/fields_of_study?departmentId.from=2&departmentId.to=4
Any errors will be indicated by a status code from the 4xx or 5xx range.
4xx errors are caused by invalid or incomplete requests, while 5xx errors are server errors.
All error responses follow a standardised format, defined and documented in-depth in /app/exceptions/base_error.ts


