diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index 1bd7bf6..0000000
--- a/.dockerignore
+++ /dev/null
@@ -1,16 +0,0 @@
-node_modules
-Dockerfile*
-docker-compose*
-.dockerignore
-.git
-.gitignore
-README.md
-LICENSE
-.vscode
-Makefile
-helm-charts
-.env
-.env.local
-.idea
-.vscode
-coverage*
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
index 955a0a1..bf64e90 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -12,5 +12,6 @@
"noUnusedLocals": true,
"noUnusedParameters": true
},
- "rules": {}
+ "rules": {},
+ "ignorePatterns": ["node_modules", "documentation"]
}
diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml
new file mode 100644
index 0000000..5028034
--- /dev/null
+++ b/.github/workflows/static.yml
@@ -0,0 +1,43 @@
+# Simple workflow for deploying static content to GitHub Pages
+name: Deploy static documentation to Pages
+
+on:
+ # Runs on pushes targeting the default branch
+ push:
+ branches: ['main']
+
+ # Allows you to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+ group: 'pages'
+ cancel-in-progress: false
+
+jobs:
+ # Single deploy job since we're just deploying
+ deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ # Upload entire repository
+ path: './documentation/generated'
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index fe8805a..621d643 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.env.local
.VSCodeCounter
node_modules
+.DS_Store
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 00a9d3c..3334bfb 100644
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1 +1 @@
-bun lint-staged
+bun lint-staged
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..b40af7a
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+documentation/generated
diff --git a/README.md b/README.md
index 9625b7c..0900fd9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,19 @@
# neuland.app-backend
-GraphQL API for the neuland.app and Neuland Next app using Apollo Server and Bun.
+Neuland API uses GraphQL to provide a flexible and powerful API for neuland.app and Neuland Next.
+
+## API Documentation
+
+The API documentation is available [here](https://neuland-ingolstadt.github.io/neuland.app-backend/).
+
+### Endpoint
+
+https://api.neuland.app
+
+> [!IMPORTANT]
+> Using the provided API endpoint outside of the neuland.app and Neuland Next app is not allowed.
+
+## Development
### Getting Started
@@ -9,12 +22,15 @@ bun i
```
Set the necessary environment variables in a `.env.local` file.
+You can use the `.env.local.example` file as a template.
+
+````bash
### Start the Development Server
```bash
bun start
-```
+````
> [!TIP]
> Use `bun dev` to start the development server with hot reloading.
@@ -31,8 +47,19 @@ http://localhost:4000/
- `index.ts` - The entry point for the API.
- `src/` - Contains the source code for the GraphQL API.
-- `src/data/` - Contains the static data for the API.
-- `src/resolvers/` - Contains the resolvers for the API.
-- `src/schema/` - Contains the type definitions for the API.
+- `src/schema.gql` - Contains the GraphQL schema.
+- `src/data/` - Contains the static data.
+- `src/resolvers/` - Contains the resolvers.
- `src/types/` - Contains the types for TypeScript.
-- `src/utils/` - Contains utility functions for the API.
+- `src/scrapers/` - Contains the scrapers for the data used by the resolvers.
+- `src/utils/` - Contains utility functions.
+
+#### Commiting Changes
+
+We use husky to lint and test the code before it is committed, that's why we recommend using the ESLint and Prettier extensions in VSCode.
+
+When changing the schema file husky will automatically generate the html documentation. Therefore, you need to have the `spectaql` package installed globally.
+
+```bash
+npm install -g spectaql
+```
diff --git a/docker-compose.yaml b/docker-compose.yaml
deleted file mode 100644
index 54dec8a..0000000
--- a/docker-compose.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-version: '3.8'
-
-services:
- app:
- build:
- context: .
- dockerfile: Dockerfile
- environment:
- - NODE_ENV=production
- ports:
- - "4000:4000"
- volumes:
- - ./.env.local:/usr/src/app/.env.local
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..26238bb
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,13 @@
+version: '3.8'
+
+services:
+ app:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ environment:
+ - NODE_ENV=production
+ ports:
+ - '4000:4000'
+ volumes:
+ - ./.env.local:/usr/src/app/.env.local
diff --git a/documentation/config.yml b/documentation/config.yml
new file mode 100644
index 0000000..4bbbe8c
--- /dev/null
+++ b/documentation/config.yml
@@ -0,0 +1,27 @@
+introspection:
+ schemaFile:
+ - ./src/schema.gql
+
+servers:
+ - url: https://api.neuland.app
+ description: Neuland API Server
+ production: true
+info:
+ title: Neuland API Documentation
+ description:
+ Neuland API uses GraphQL to provide a flexible and powerful API for neuland.app and Neuland Next.
+ This documentation provides a detailed overview of the API and its capabilities.
+ Using the provided API endpoint outside of the neuland.app and Neuland Next app is not allowed.
+ termsOfService: 'https://assets.neuland.app/datenschutzerklaerung-app.pdf'
+ contact:
+ name: Neuland Ingolstadt e.V.
+ email: info@neuland-ingolstadt.de
+ url: https://github.com/neuland-ingolstadt/neuland.app-backend
+ license:
+ name: AGPL-3.0
+ url: 'https://www.gnu.org/licenses/agpl-3.0.html'
+spectaql:
+ faviconFile: ./documentation/icon.svg
+ theme: spectaql
+ logoFile: ./documentation/icon.svg
+ targetDir: ./documentation/generated
diff --git a/documentation/generated/images/favicon.svg b/documentation/generated/images/favicon.svg
new file mode 100644
index 0000000..db8c27d
--- /dev/null
+++ b/documentation/generated/images/favicon.svg
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/generated/images/logo.svg b/documentation/generated/images/logo.svg
new file mode 100644
index 0000000..db8c27d
--- /dev/null
+++ b/documentation/generated/images/logo.svg
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/documentation/generated/index.html b/documentation/generated/index.html
new file mode 100644
index 0000000..8486099
--- /dev/null
+++ b/documentation/generated/index.html
@@ -0,0 +1,1846 @@
+
+
+
+
+
+
+ Neuland API Documentation
+
+
+
+
+
+
+
+
+
+
+
+ Neuland API Documentation
+
+
+
+
Neuland API uses GraphQL to provide a flexible and powerful API for neuland.app and Neuland Next. This documentation provides a detailed overview of the API and its capabilities. Using the provided API endpoint outside of the neuland.app and Neuland Next app is not allowed.
+
+
+
+
+
+
+
API Endpoints
+
https://api.neuland.app
+
+
+
+
+ Queries
+
+
+ announcements
+
+
+
+
+
Description
+
Get the current announcements
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query announcements {
+ announcements {
+ title {
+ ...MultiLanguageStringFragment
+ }
+ description {
+ ...MultiLanguageStringFragment
+ }
+ startDateTime
+ endDateTime
+ priority
+ url
+ }
+}
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "announcements" : [
+ {
+ "title" : MultiLanguageString ,
+ "description" : MultiLanguageString ,
+ "startDateTime" : "xyz789" ,
+ "endDateTime" : "xyz789" ,
+ "priority" : 123 ,
+ "url" : "abc123"
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ bus
+
+
+
+
+
Description
+
Get the current bus departures at a specific station
+
+
+
+
+
+
+
+
Arguments
+
+
+
+ Name
+ Description
+
+
+
+
+
+ station
- String!
+
+
+
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query bus($station : String! ) {
+ bus(station: $station ) {
+ route
+ destination
+ time
+ }
+}
+
+
+
+
+
+
Variables
+
+
+
{ "station" : "xyz789" }
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "bus" : [
+ {
+ "route" : "xyz789" ,
+ "destination" : "xyz789" ,
+ "time" : "abc123"
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ charging
+
+
+
+
+
Description
+
Get the current electric vehicle charging stations in Ingolstadt
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query charging {
+ charging {
+ id
+ name
+ address
+ city
+ latitude
+ longitude
+ available
+ total
+ freeParking
+ operator
+ }
+}
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "charging" : [
+ {
+ "id" : 987 ,
+ "name" : "abc123" ,
+ "address" : "abc123" ,
+ "city" : "xyz789" ,
+ "latitude" : 123.45 ,
+ "longitude" : 987.65 ,
+ "available" : 123 ,
+ "total" : 987 ,
+ "freeParking" : false ,
+ "operator" : "abc123"
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ clEvents
+
+
+
+
+
Description
+
Get the campus life events
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query clEvents {
+ clEvents {
+ id
+ organizer
+ title
+ begin
+ end
+ }
+}
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "clEvents" : [
+ {
+ "id" : 4 ,
+ "organizer" : "abc123" ,
+ "title" : "abc123" ,
+ "begin" : "abc123" ,
+ "end" : "xyz789"
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ food
+
+
+
+
+
Description
+
Get the meal plan for a specific restaurant
+
+
+
+
+
+
+
+
Arguments
+
+
+
+ Name
+ Description
+
+
+
+
+
+ locations
- [String!]
+
+
+
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query food($locations : [String! ]) {
+ food(locations: $locations ) {
+ timestamp
+ meals {
+ ...MealFragment
+ }
+ }
+}
+
+
+
+
+
+
Variables
+
+
+
{ "locations" : [ "abc123" ] }
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "food" : [
+ {
+ "timestamp" : "xyz789" ,
+ "meals" : [ Meal ]
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ parking
+
+
+
+
+
Description
+
Get the current parking data in Ingolstadt
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query parking {
+ parking {
+ updated
+ lots {
+ ...ParkingLotFragment
+ }
+ }
+}
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "parking" : {
+ "updated" : "abc123" ,
+ "lots" : [ ParkingLot ]
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+ train
+
+
+
+
+
Description
+
Get the current train departures at a specific station
+
+
+
+
+
+
+
+
Arguments
+
+
+
+ Name
+ Description
+
+
+
+
+
+ station
- String!
+
+
+
+
+
+
+
+
+
+
Example
+
+
Query
+
+
+
query train($station : String! ) {
+ train(station: $station ) {
+ name
+ destination
+ plannedTime
+ actualTime
+ canceled
+ track
+ url
+ }
+}
+
+
+
+
+
+
Variables
+
+
+
{ "station" : "xyz789" }
+
+
+
+
+
+
Response
+
+
+
{
+ "data" : {
+ "train" : [
+ {
+ "name" : "xyz789" ,
+ "destination" : "xyz789" ,
+ "plannedTime" : "abc123" ,
+ "actualTime" : "xyz789" ,
+ "canceled" : true ,
+ "track" : "abc123" ,
+ "url" : "xyz789"
+ }
+ ]
+ }
+}
+
+
+
+
+
+
+
+ Types
+
+ Announcement
+
+
+
+
Description
+
Announcement data to display on top of the apps dashboard
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ title
- MultiLanguageString!
+
+ Title of the announcement in different languages
+
+
+ description
- MultiLanguageString!
+
+ Description of the announcement in different languages
+
+
+ startDateTime
- String!
+
+ Start date and time when the announcement is displayed
+
+
+ endDateTime
- String!
+
+ End date and time when the announcement is displayed
+
+
+ priority
- Int!
+
+ Priority of the announcement, higher are more important
+
+
+ url
- String
+
+ URL to the announcement
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "title" : MultiLanguageString ,
+ "description" : MultiLanguageString ,
+ "startDateTime" : "xyz789" ,
+ "endDateTime" : "xyz789" ,
+ "priority" : 123 ,
+ "url" : "xyz789"
+}
+
+
+
+
+
+
+
+
+
+ Boolean
+
+
+
+
Description
+
The Boolean
scalar type represents true
or false
.
+
+
+
+
+
+
+
+
+ Bus
+
+
+
+
Description
+
Charging station data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ route
- String!
+
+ Code of the bus route, like 10, N1, etc.
+
+
+ destination
- String!
+
+ Destination of the bus route
+
+
+ time
- String!
+
+ Planned time at the station
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "route" : "xyz789" ,
+ "destination" : "abc123" ,
+ "time" : "xyz789"
+}
+
+
+
+
+
+
+
+
+
+ ChargingStation
+
+
+
+
Description
+
Charging station data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ id
- Int!
+
+ Unique identifier of the charging station
+
+
+ name
- String!
+
+ Name of the charging station
+
+
+ address
- String!
+
+ Address of the charging station
+
+
+ city
- String!
+
+ City of the charging station
+
+
+ latitude
- Float!
+
+ Latitude of the charging station
+
+
+ longitude
- Float!
+
+ Longitude of the charging station
+
+
+ available
- Int!
+
+ Number of available charging points
+
+
+ total
- Int!
+
+ Number of total charging points
+
+
+ freeParking
- Boolean
+
+ True if the charging is labeled as free parking
+
+
+ operator
- String
+
+ Operator of the charging station
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "id" : 987 ,
+ "name" : "xyz789" ,
+ "address" : "abc123" ,
+ "city" : "xyz789" ,
+ "latitude" : 987.65 ,
+ "longitude" : 123.45 ,
+ "available" : 123 ,
+ "total" : 123 ,
+ "freeParking" : true ,
+ "operator" : "xyz789"
+}
+
+
+
+
+
+
+
+
+
+ ClEvent
+
+
+
+
Description
+
Campus Life Event
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ id
- ID!
+
+ Unique identifier of the event
+
+
+ organizer
- String!
+
+ Organizer of the event
+
+
+ title
- String!
+
+ Title of the event in German
+
+
+ begin
- String
+
+ Begin of the event
+
+
+ end
- String
+
+ End of the event
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "id" : "4" ,
+ "organizer" : "abc123" ,
+ "title" : "abc123" ,
+ "begin" : "abc123" ,
+ "end" : "xyz789"
+}
+
+
+
+
+
+
+
+
+
+ Float
+
+
+
+
Description
+
The Float
scalar type represents signed double-precision fractional values as specified by IEEE 754 .
+
+
+
+
+
Example
+
+
+
987.65
+
+
+
+
+
+
+
+
+
+ Food
+
+
+
+
Description
+
Provides a list of meals for a specific day
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ timestamp
- String!
+
+ Date of the meal list
+
+
+ meals
- [Meal!]
+
+ List of meals
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "timestamp" : "xyz789" ,
+ "meals" : [ Meal ]
+}
+
+
+
+
+
+
+
+
+
+ ID
+
+
+
+
Description
+
The ID
scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4"
) or integer (such as 4
) input value will be accepted as an ID.
+
+
+
+
+
Example
+
+
+
4
+
+
+
+
+
+
+
+
+
+ Int
+
+
+
+
Description
+
The Int
scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
+
+
+
+
+
Example
+
+
+
987
+
+
+
+
+
+
+
+
+
+ Meal
+
+
+
+
Description
+
Meal data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ name
- MultiLanguageString!
+
+ Name of the meal in different languages
+
+
+ id
- ID!
+
+ Unique identifier of the meal
+
+
+ category
- String!
+
+ Category of the meal (main, soup or salad)
+
+
+ prices
- Prices!
+
+ Prices for different types of customers (student, employee, guest)
+
+
+ allergens
- [String]
+
+ List of allergens (e.g. gluten, lactose, etc.)
+
+
+ flags
- [String]
+
+ List of flags (e.g. vegan, vegetarian, etc.)
+
+
+ nutrition
- Nutrition
+
+ Nutritional values for the meal
+
+
+ variants
- [Variation!]
+
+ Variants or toppings of the meal, like bread, sauce, etc.
+
+
+ originalLanguage
- OriginalLanguage!
+
+ Original language of the meal name
+
+
+ static
- Boolean!
+
+ Static meals are always available, non-static meals are only available on specific days
+
+
+ restaurant
- String!
+
+ Restaurant where the meal is available (mensa, reimanns or canisius)
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "name" : MultiLanguageString ,
+ "id" : 4 ,
+ "category" : "abc123" ,
+ "prices" : Prices ,
+ "allergens" : [ "abc123" ] ,
+ "flags" : [ "xyz789" ] ,
+ "nutrition" : Nutrition ,
+ "variants" : [ Variation ] ,
+ "originalLanguage" : "de" ,
+ "static" : false ,
+ "restaurant" : "abc123"
+}
+
+
+
+
+
+
+
+
+
+ MultiLanguageString
+
+
+
+
Description
+
String in multiple languages (German and English)
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ de
- String
+
+ German language code
+
+
+ en
- String
+
+ English language code
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "de" : "xyz789" ,
+ "en" : "abc123"
+}
+
+
+
+
+
+
+
+
+
+ Nutrition
+
+
+
+
Description
+
Nutritional values for a meal. Currently only available at Mensa. Values are per average portion.
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ kj
- Float!
+
+ Energy in kilojoules
+
+
+ kcal
- Float!
+
+ Energy in kilocalories
+
+
+ fat
- Float!
+
+ Fat in grams
+
+
+ fatSaturated
- Float!
+
+ Saturated fat in grams
+
+
+ carbs
- Float!
+
+ Carbohydrates in grams
+
+
+ sugar
- Float!
+
+ Sugar in grams
+
+
+ fiber
- Float!
+
+ Fiber in grams
+
+
+ protein
- Float!
+
+ Protein in grams
+
+
+ salt
- Float!
+
+ Salt in grams
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "kj" : 987.65 ,
+ "kcal" : 987.65 ,
+ "fat" : 987.65 ,
+ "fatSaturated" : 123.45 ,
+ "carbs" : 123.45 ,
+ "sugar" : 987.65 ,
+ "fiber" : 987.65 ,
+ "protein" : 123.45 ,
+ "salt" : 123.45
+}
+
+
+
+
+
+
+
+
+
+ OriginalLanguage
+
+
+
+
Description
+
Original language of the meal name
+
+
+
Values
+
+
+
+ Enum Value
+ Description
+
+
+
+
+
+ de
+
+ German language code
+
+
+
+ en
+
+ English language code
+
+
+
+
+
+
+
+
Example
+
+
+
"de"
+
+
+
+
+
+
+
+
+
+ Parent
+
+
+
+
Description
+
Parent meal for a variant meal
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ id
- ID!
+
+ Unique identifier of the parent meal
+
+
+ category
- String!
+
+ Category of the parent meal (main, soup or salad)
+
+
+ name
- MultiLanguageString!
+
+ Name of the parent meal in different languages
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "id" : "4" ,
+ "category" : "xyz789" ,
+ "name" : MultiLanguageString
+}
+
+
+
+
+
+
+
+
+
+ ParkingData
+
+
+
+
Description
+
Parking data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ updated
- String!
+
+ Timestamp of the last update from the source
+
+
+ lots
- [ParkingLot!]!
+
+ List of parking lots
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "updated" : "abc123" ,
+ "lots" : [ ParkingLot ]
+}
+
+
+
+
+
+
+
+
+
+ ParkingLot
+
+
+
+
Description
+
Parking lot data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ name
- String!
+
+ Name of the parking lot
+
+
+ available
- Int!
+
+ Number of available parking spaces
+
+
+ priceLevel
- Int
+
+ Price level of the parking lot between 0 (free) and 3 (expensive)
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "name" : "xyz789" ,
+ "available" : 987 ,
+ "priceLevel" : 987
+}
+
+
+
+
+
+
+
+
+
+ Prices
+
+
+
+
Description
+
Prices for different types of customers
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ student
- Float!
+
+ Price for students
+
+
+ employee
- Float!
+
+ Price for employees
+
+
+ guest
- Float!
+
+ Price for guests
+
+
+
+
+
+
+
+
Example
+
+
+
{ "student" : 987.65 , "employee" : 987.65 , "guest" : 987.65 }
+
+
+
+
+
+
+
+
+
+ String
+
+
+
+
Description
+
The String
scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
+
+
+
+
+
Example
+
+
+
"xyz789"
+
+
+
+
+
+
+
+
+
+ Train
+
+
+
+
Description
+
Train data
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ name
- String!
+
+ Name of the train
+
+
+ destination
- String!
+
+ Destination of the train
+
+
+ plannedTime
- String!
+
+ Planned departure time
+
+
+ actualTime
- String!
+
+ Actual departure time
+
+
+ canceled
- Boolean!
+
+ True if the train is canceled
+
+
+ track
- String
+
+ Track of the train
+
+
+ url
- String
+
+ URL to the train information
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "name" : "xyz789" ,
+ "destination" : "xyz789" ,
+ "plannedTime" : "abc123" ,
+ "actualTime" : "abc123" ,
+ "canceled" : true ,
+ "track" : "abc123" ,
+ "url" : "xyz789"
+}
+
+
+
+
+
+
+
+
+
+ Variation
+
+
+
+
Description
+
Variants of a meal
+
+
+
Fields
+
+
+
+ Field Name
+ Description
+
+
+
+
+ name
- MultiLanguageString!
+
+ Name of the variant in different languages
+
+
+ additional
- Boolean!
+
+ True if the variant is an additional topping and not a variant of the meal
+
+
+ prices
- Prices!
+
+ Prices for different types of customers (student, employee, guest)
+
+
+ id
- ID!
+
+ Unique identifier of the variant
+
+
+ allergens
- [String]
+
+ List of allergens (e.g. gluten, lactose, etc.)
+
+
+ flags
- [String]
+
+ List of flags (e.g. vegan, vegetarian, etc.)
+
+
+ nutrition
- Nutrition
+
+ Nutritional values for the variant
+
+
+ originalLanguage
- OriginalLanguage!
+
+ Original language of the variant name
+
+
+ static
- Boolean!
+
+ Static variants are always available, non-static variants are only available on specific days
+
+
+ restaurant
- String
+
+ Restaurant where the variant is available (mensa, reimanns or canisius)
+
+
+ parent
- Parent
+
+ Parent meal for a variant meal
+
+
+
+
+
+
+
+
Example
+
+
+
{
+ "name" : MultiLanguageString ,
+ "additional" : true ,
+ "prices" : Prices ,
+ "id" : "4" ,
+ "allergens" : [ "xyz789" ] ,
+ "flags" : [ "abc123" ] ,
+ "nutrition" : Nutrition ,
+ "originalLanguage" : "de" ,
+ "static" : false ,
+ "restaurant" : "xyz789" ,
+ "parent" : Parent
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/documentation/generated/javascripts/spectaql.min.js b/documentation/generated/javascripts/spectaql.min.js
new file mode 100644
index 0000000..0b7aea0
--- /dev/null
+++ b/documentation/generated/javascripts/spectaql.min.js
@@ -0,0 +1 @@
+"use strict";function scrollSpy(){var c=5,e=document.querySelector("html"),l=(e&&(e=window.getComputedStyle(e).scrollPaddingTop)&&"string"==typeof e&&"auto"!==e&&e.endsWith("px")&&(c+=parseInt(e.split("px")[0])),"nav-scroll-active"),i=null,d=[];function t(){i=null;var e=document.querySelectorAll("[data-traverse-target]");Array.prototype.forEach.call(e,function(e){d.push({id:e.id,top:e.offsetTop})})}var n=debounce(function(){t(),o()},500),o=debounce(function(){var e,t,n,o,r=function(e){for(var t=e+c,n=0;n=d[n].top&&(!o||t{toggleMenu(),scrollSpy()});
\ No newline at end of file
diff --git a/documentation/generated/stylesheets/spectaql.min.css b/documentation/generated/stylesheets/spectaql.min.css
new file mode 100644
index 0000000..5859df8
--- /dev/null
+++ b/documentation/generated/stylesheets/spectaql.min.css
@@ -0,0 +1 @@
+#spectaql{padding:0;margin:0}#spectaql pre{overflow:auto;margin-top:0;margin-bottom:20px}#spectaql pre code{display:block;background:#ccc}#spectaql table{width:100%;table-layout:fixed;text-align:left;border-collapse:collapse}#spectaql table td,#spectaql table th{margin:0;padding:0}#spectaql #introduction .example-section>*,#spectaql .definition-heading,#spectaql .doc-heading,#spectaql .introduction-item-title,#spectaql .operation-heading{overflow:hidden;text-overflow:ellipsis}#spectaql #page{display:flex}#spectaql #page *{box-sizing:border-box}#spectaql #page.drawer-open #sidebar{z-index:1000;transform:translateX(0)}#spectaql #page.drawer-open .drawer-overlay{display:block;background:rgba(0,0,0,.5);z-index:10}#spectaql #sidebar{position:fixed;min-width:250px;max-width:250px;flex-shrink:0;transition:transform .2s ease-out;transform:translateX(-100%);z-index:10;padding-top:20px;background:#fff}@media (min-width:48em){#spectaql #sidebar{position:relative;transform:none}}@media (min-width:64em){#spectaql #sidebar{min-width:300px;max-width:300px}}#spectaql .sidebar-top-container{display:flex;align-items:center;padding:0 20px}#spectaql #mobile-navbar{display:flex;align-items:center;position:sticky;top:0}@media (min-width:48em){#spectaql #mobile-navbar{display:none}}#spectaql .sidebar-open-button{display:flex;align-items:flex-start;margin:0;padding:0;border:none;background:0 0}#spectaql .sidebar-open-button .hamburger{width:16px;height:14px;cursor:pointer}#spectaql .sidebar-open-button .hamburger::after{display:block;content:"";height:2px;background:#222;box-shadow:0 5px 0 #222,0 10px 0 #222}#spectaql .sidebar-open-button .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}#spectaql .close-button{display:block}#spectaql .close-button .sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media (min-width:48em){#spectaql .close-button{display:none}}#spectaql .drawer-overlay{display:none;position:absolute;top:0;left:0;bottom:0;right:0;background:rgba(0,0,0,0)}@media (min-width:48em){#spectaql .drawer-overlay{display:none!important}}#spectaql #nav{display:flex;flex-direction:column;max-height:calc(100vh - 0px);padding:0 20px;padding-bottom:20px;position:sticky;top:0;overflow:auto}#spectaql #logo{margin-right:auto}#spectaql #logo img{display:block;width:100%;max-width:100%}#spectaql .nav-group-items,#spectaql .nav-group-section-items{padding:0;margin:0}#spectaql .nav-group-items>li,#spectaql .nav-group-section-items>li{list-style:none}#spectaql .nav-group-items .nav-group-section-title,#spectaql .nav-group-items>li,#spectaql .nav-group-section-items .nav-group-section-title,#spectaql .nav-group-section-items>li{overflow:hidden;text-overflow:ellipsis}#spectaql .nav-group-section-items{display:none}#spectaql .nav-scroll-expand .nav-group-section-items{display:block}#spectaql #docs{position:relative;margin:0 auto;min-width:100px;max-width:88em;flex-grow:1;flex-shrink:1;padding:20px}@media (min-width:48em){#spectaql .doc-row{display:flex;flex-wrap:wrap}}#spectaql .doc-row .doc-copy,#spectaql .doc-row .doc-examples{width:100%}@media (min-width:48em){#spectaql .doc-row .doc-copy,#spectaql .doc-row .doc-examples{width:50%}}@media (min-width:48em){#spectaql .doc-row .doc-copy{padding-right:20px}}@media (min-width:48em){#spectaql .doc-row .doc-examples{padding-left:20px}}.hljs{display:block;overflow-x:auto;padding:.5em;background:#23241f}.hljs,.hljs-subst,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong{color:#a8a8a2}.hljs-bullet,.hljs-link,.hljs-literal,.hljs-number,.hljs-quote,.hljs-regexp{color:#ae81ff}.hljs-code,.hljs-section,.hljs-selector-class,.hljs-title{color:#a6e22e}.hljs-strong{font-weight:700}.hljs-emphasis{font-style:italic}.hljs-attr,.hljs-keyword,.hljs-name,.hljs-selector-tag{color:#f92672}.hljs-attribute,.hljs-symbol{color:#66d9ef}.hljs-class .hljs-title,.hljs-params{color:#f8f8f2}.hljs-addition,.hljs-built_in,.hljs-builtin-name,.hljs-selector-attr,.hljs-selector-id,.hljs-selector-pseudo,.hljs-string,.hljs-template-variable,.hljs-type,.hljs-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e}#spectaql{font-family:-apple-system,BlinkMacSystemFont,system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:14px;line-height:1.6;background:#fff;color:#222}@media (min-width:32em){#spectaql{font-size:16px}}#spectaql a{color:#0298bf;text-decoration:none}#spectaql a:hover{color:#0182a2}#spectaql a:active,#spectaql a:focus{color:#0298bf}#spectaql code{font-size:.875em;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace}#spectaql pre{color:#fff}#spectaql pre code{background:#222}#spectaql pre code,#spectaql pre code.hljs{font-size:.82em;line-height:1.4;padding:15px 20px}#spectaql .doc-heading{line-height:1.2;font-size:2.25em;margin-top:10px}@media (min-width:48em){#spectaql .doc-heading{margin-top:-10px}}#spectaql .close-button{background:0 0;border:none;padding:5px;font-size:16px;font-weight:700;color:#222}#spectaql #introduction{margin-bottom:60px}#spectaql #introduction .example-section:not(.example-section-is-code){margin-bottom:20px}#spectaql #introduction .example-section:not(.example-section-is-code) h5,#spectaql #introduction .example-section:not(.example-section-is-code) p{margin:0;font-size:1em}#spectaql #docs,#spectaql #mobile-navbar,#spectaql #sidebar{padding-top:20px;padding-bottom:20px}@media (min-width:32em){#spectaql #docs,#spectaql #mobile-navbar,#spectaql #sidebar{padding-top:30px;padding-bottom:30px}}@media (min-width:48em){#spectaql #docs,#spectaql #mobile-navbar,#spectaql #sidebar{padding-top:40px;padding-bottom:40px}}#spectaql #docs,#spectaql #mobile-navbar,#spectaql #nav,#spectaql .sidebar-top-container{padding-left:20px;padding-right:20px}@media (min-width:32em){#spectaql #docs,#spectaql #mobile-navbar,#spectaql #nav,#spectaql .sidebar-top-container{padding-left:30px;padding-right:30px}}@media (min-width:48em){#spectaql #docs,#spectaql #mobile-navbar,#spectaql #nav,#spectaql .sidebar-top-container{padding-left:50px;padding-right:50px}}#spectaql #sidebar{padding-bottom:0;background:#fff}#spectaql #sidebar a{color:#222}#spectaql #sidebar a.nav-scroll-active,#spectaql #sidebar a:hover{font-weight:700}#spectaql #sidebar a.nav-scroll-active{color:#222}#spectaql #sidebar a:hover{color:#0182a2}@media (min-width:48em){#spectaql #sidebar{border-right:2px solid #d8d8d8}}#spectaql #mobile-navbar{background:#fff;margin-top:-20px;margin-left:-20px;margin-right:-20px}@media (min-width:32em){#spectaql #mobile-navbar{margin-top:-30px;margin-left:-30px;margin-right:-30px}}#spectaql #mobile-navbar .sidebar-open-button::after{display:block;content:"All Topics";margin-left:10px;color:#222}#spectaql #nav .nav-group{margin-top:20px}#spectaql #nav .nav-group li{margin-bottom:5px}#spectaql #nav .nav-group-title{font-size:.875em;font-weight:400;margin:0 0 6px 0;color:#999}#spectaql #nav .nav-group-section-title{font-size:inherit;margin:0;margin-bottom:5px;font-weight:400}#spectaql #nav .nav-group-section-items{margin-left:.75em}#spectaql .definition,#spectaql .operation{margin-bottom:60px}#spectaql .definition .definition-heading,#spectaql .definition .operation-heading,#spectaql .operation .definition-heading,#spectaql .operation .operation-heading{font-size:1.72em}#spectaql .definition .definition-heading code,#spectaql .definition .operation-heading code,#spectaql .operation .definition-heading code,#spectaql .operation .operation-heading code{font-family:inherit;font-size:inherit;font-weight:inherit}@media (min-width:32em){#spectaql .definition .definition-heading,#spectaql .definition .operation-heading,#spectaql .operation .definition-heading,#spectaql .operation .operation-heading{font-size:2.25em}}#spectaql .definition-group-name,#spectaql .group-heading,#spectaql .operation-group-name{border-top:2px solid #d8d8d8;padding-top:3px;color:#999;font-size:inherit;font-weight:inherit}#spectaql .definition-group-name a,#spectaql .group-heading a,#spectaql .operation-group-name a{color:#999}#spectaql .definition-group-name a:hover,#spectaql .group-heading a:hover,#spectaql .operation-group-name a:hover{font-weight:700}#spectaql .doc-examples{margin-top:20px}#spectaql .doc-examples .example-heading{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}#spectaql .doc-examples .example-section-is-code h5{color:#999;text-transform:uppercase;background:#000;font-size:.75em;font-weight:700;padding:.6em 0 .6em 20px;margin:0;opacity:1}@media (min-width:48em){#spectaql .doc-examples{margin-top:0}}#spectaql .doc-copy p{margin:0 0 20px 0}#spectaql .doc-copy p:last-child{margin-bottom:0}#spectaql .doc-copy table tr th{font-weight:400;border-bottom:2px solid #d8d8d8}#spectaql .doc-copy table tr td{border-bottom:1px solid #e0e0e0}#spectaql .doc-copy table tr.row-has-field-arguments td,#spectaql .doc-copy table tr:last-child td{border-bottom:none}#spectaql .doc-copy table tr td,#spectaql .doc-copy table tr th{padding:5px}#spectaql .doc-copy table tr td:first-child,#spectaql .doc-copy table tr th:first-child{padding-left:0}#spectaql .doc-copy table tr td:last-child,#spectaql .doc-copy table tr th:last-child{padding-right:0}#spectaql .doc-copy .doc-copy-section{margin-bottom:30px}#spectaql .doc-copy .doc-copy-section>h5{margin:0 0 5px 0;font-size:inherit;font-weight:inherit;color:#999}#spectaql .doc-copy .definition-description>h5,#spectaql .doc-copy .definition-properties>h5,#spectaql .doc-copy .operation-description>h5{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}#spectaql .field-arguments{font-size:.875em;background-color:#fafbfc;border:1px solid #e0e0e0;padding:10px;margin-bottom:5px}#spectaql .field-arguments p{margin:10px 0 0 0}#spectaql .field-arguments h5.field-arguments-heading{margin:0;padding:0 0 10px 0;font-weight:inherit;color:#999}#spectaql .field-arguments .field-argument{border-top:1px #e0e0e0 solid;padding:10px 0}#spectaql .field-arguments .field-argument:last-child{padding-bottom:0}#spectaql .field-arguments .field-argument-name{margin:0;font-size:inherit;font-weight:inherit}#spectaql .deprecation-reason{word-break:break-word}#spectaql .deprecation-reason::before{display:inline;content:"Deprecated";padding:2px 5px;margin-right:5px;background:#fed7d8;color:#c60609;font-weight:700;font-size:.875em}
\ No newline at end of file
diff --git a/documentation/icon.svg b/documentation/icon.svg
new file mode 100644
index 0000000..db8c27d
--- /dev/null
+++ b/documentation/icon.svg
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/index.ts b/index.ts
index 84fe577..5768005 100644
--- a/index.ts
+++ b/index.ts
@@ -4,10 +4,12 @@ import {
ApolloServerPluginLandingPageProductionDefault,
} from '@apollo/server/plugin/landingPage/default'
import { apolloIntegration } from '@chrisenglert/as-integrations-bun'
+import { readFileSync } from 'fs'
import NodeCache from 'node-cache'
import { resolvers } from './src/resolvers'
-import { typeDefs } from './src/schema'
+
+const typeDefs = readFileSync('./src/schema.gql', { encoding: 'utf-8' })
const apolloServer = new ApolloServer({
typeDefs,
diff --git a/package.json b/package.json
index d74c5fb..a1031a5 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,8 @@
"scripts": {
"start": "bun run index.ts",
"dev": "bun --hot run index.ts",
- "prepare": "husky"
+ "prepare": "husky",
+ "docs": "bunx spectaql ./documentation/config.yml"
},
"peerDependencies": {
"typescript": "^5.0.0"
@@ -42,10 +43,14 @@
"typescript": "^5.4.4"
},
"lint-staged": {
+ "**/*.{gql,graphql}": [
+ "bun docs",
+ "git add documentation/generated"
+ ],
"**/*.{js,jsx,ts,tsx}": [
"bunx eslint --fix"
],
- "**/*.{js,jsx,ts,tsx,json,yml}": [
+ "**/*.{js,jsx,ts,tsx,json,yml,gql,graphql,md}": [
"bunx prettier --write"
]
}
diff --git a/src/schema.gql b/src/schema.gql
new file mode 100644
index 0000000..5decdd2
--- /dev/null
+++ b/src/schema.gql
@@ -0,0 +1,439 @@
+"""
+Charging station data
+"""
+type ChargingStation {
+ """
+ Unique identifier of the charging station
+ """
+ id: Int!
+ """
+ Name of the charging station
+ """
+ name: String!
+ """
+ Address of the charging station
+ """
+ address: String!
+ """
+ City of the charging station
+ """
+ city: String!
+ """
+ Latitude of the charging station
+ """
+ latitude: Float!
+ """
+ Longitude of the charging station
+ """
+ longitude: Float!
+ """
+ Number of available charging points
+ """
+ available: Int!
+ """
+ Number of total charging points
+ """
+ total: Int!
+ """
+ True if the charging is labeled as free parking
+ """
+ freeParking: Boolean
+ """
+ Operator of the charging station
+ """
+ operator: String
+}
+
+"""
+Parking data
+"""
+type ParkingData {
+ """
+ Timestamp of the last update from the source
+ """
+ updated: String!
+ """
+ List of parking lots
+ """
+ lots: [ParkingLot!]!
+}
+
+"""
+Parking lot data
+"""
+type ParkingLot {
+ """
+ Name of the parking lot
+ """
+ name: String!
+ """
+ Number of available parking spaces
+ """
+ available: Int!
+ """
+ Price level of the parking lot between 0 (free) and 3 (expensive)
+ """
+ priceLevel: Int
+}
+
+"""
+Meal data
+"""
+type Meal {
+ """
+ Name of the meal in different languages
+ """
+ name: MultiLanguageString!
+ """
+ Unique identifier of the meal
+ """
+ id: ID!
+ """
+ Category of the meal (main, soup or salad)
+ """
+ category: String!
+ """
+ Prices for different types of customers (student, employee, guest)
+ """
+ prices: Prices!
+ """
+ List of allergens (e.g. gluten, lactose, etc.)
+ """
+ allergens: [String]
+ """
+ List of flags (e.g. vegan, vegetarian, etc.)
+ """
+ flags: [String]
+ """
+ Nutritional values for the meal
+ """
+ nutrition: Nutrition
+ """
+ Variants or toppings of the meal, like bread, sauce, etc.
+ """
+ variants: [Variation!]
+ """
+ Original language of the meal name
+ """
+ originalLanguage: OriginalLanguage!
+ """
+ Static meals are always available, non-static meals are only available on specific days
+ """
+ static: Boolean!
+ """
+ Restaurant where the meal is available (mensa, reimanns or canisius)
+ """
+ restaurant: String!
+}
+
+"""
+Variants of a meal
+"""
+type Variation {
+ """
+ Name of the variant in different languages
+ """
+ name: MultiLanguageString!
+ """
+ True if the variant is an additional topping and not a variant of the meal
+ """
+ additional: Boolean!
+ """
+ Prices for different types of customers (student, employee, guest)
+ """
+ prices: Prices!
+ """
+ Unique identifier of the variant
+ """
+ id: ID!
+ """
+ List of allergens (e.g. gluten, lactose, etc.)
+ """
+ allergens: [String]
+ """
+ List of flags (e.g. vegan, vegetarian, etc.)
+ """
+ flags: [String]
+ """
+ Nutritional values for the variant
+ """
+ nutrition: Nutrition
+ """
+ Original language of the variant name
+ """
+ originalLanguage: OriginalLanguage!
+ """
+ Static variants are always available, non-static variants are only available on specific days
+ """
+ static: Boolean!
+ """
+ Restaurant where the variant is available (mensa, reimanns or canisius)
+ """
+ restaurant: String
+ """
+ Parent meal for a variant meal
+ """
+ parent: Parent
+}
+
+"""
+Nutritional values for a meal. Currently only available at Mensa. Values are per average portion.
+"""
+type Nutrition {
+ """
+ Energy in kilojoules
+ """
+ kj: Float!
+ """
+ Energy in kilocalories
+ """
+ kcal: Float!
+ """
+ Fat in grams
+ """
+ fat: Float!
+ """
+ Saturated fat in grams
+ """
+ fatSaturated: Float!
+ """
+ Carbohydrates in grams
+ """
+ carbs: Float!
+ """
+ Sugar in grams
+ """
+ sugar: Float!
+ """
+ Fiber in grams
+ """
+ fiber: Float!
+ """
+ Protein in grams
+ """
+ protein: Float!
+ """
+ Salt in grams
+ """
+ salt: Float!
+}
+
+"""
+Original language of the meal name
+"""
+enum OriginalLanguage {
+ """
+ German language code
+ """
+ de
+ """
+ English language code
+ """
+ en
+}
+
+"""
+Prices for different types of customers
+"""
+type Prices {
+ """
+ Price for students
+ """
+ student: Float!
+ """
+ Price for employees
+ """
+ employee: Float!
+ """
+ Price for guests
+ """
+ guest: Float!
+}
+
+"""
+Provides a list of meals for a specific day
+"""
+type Food {
+ """
+ Date of the meal list
+ """
+ timestamp: String!
+ """
+ List of meals
+ """
+ meals: [Meal!]
+}
+
+"""
+Parent meal for a variant meal
+"""
+type Parent {
+ """
+ Unique identifier of the parent meal
+ """
+ id: ID!
+ """
+ Category of the parent meal (main, soup or salad)
+ """
+ category: String!
+ """
+ Name of the parent meal in different languages
+ """
+ name: MultiLanguageString!
+}
+
+"""
+Campus Life Event
+"""
+type ClEvent {
+ """
+ Unique identifier of the event
+ """
+ id: ID!
+ """
+ Organizer of the event
+ """
+ organizer: String!
+ """
+ Title of the event in German
+ """
+ title: String!
+ """
+ Begin of the event
+ """
+ begin: String
+ """
+ End of the event
+ """
+ end: String
+}
+
+"""
+Charging station data
+"""
+type Bus {
+ """
+ Code of the bus route, like 10, N1, etc.
+ """
+ route: String!
+ """
+ Destination of the bus route
+ """
+ destination: String!
+ """
+ Planned time at the station
+ """
+ time: String!
+}
+
+"""
+Train data
+"""
+type Train {
+ """
+ Name of the train
+ """
+ name: String!
+ """
+ Destination of the train
+ """
+ destination: String!
+ """
+ Planned departure time
+ """
+ plannedTime: String!
+ """
+ Actual departure time
+ """
+ actualTime: String!
+ """
+ True if the train is canceled
+ """
+ canceled: Boolean!
+ """
+ Track of the train
+ """
+ track: String
+ """
+ URL to the train information
+ """
+ url: String
+}
+
+"""
+Announcement data to display on top of the apps dashboard
+"""
+type Announcement {
+ """
+ Title of the announcement in different languages
+ """
+ title: MultiLanguageString!
+ """
+ Description of the announcement in different languages
+ """
+ description: MultiLanguageString!
+ """
+ Start date and time when the announcement is displayed
+ """
+ startDateTime: String!
+ """
+ End date and time when the announcement is displayed
+ """
+ endDateTime: String!
+ """
+ Priority of the announcement, higher are more important
+ """
+ priority: Int!
+ """
+ URL to the announcement
+ """
+ url: String
+}
+
+"""
+String in multiple languages (German and English)
+"""
+type MultiLanguageString {
+ """
+ German language code
+ """
+ de: String
+ """
+ English language code
+ """
+ en: String
+}
+
+"""
+Root query
+"""
+type Query {
+ """
+ Get the current parking data in Ingolstadt
+ """
+ parking: ParkingData
+ """
+ Get the current electric vehicle charging stations in Ingolstadt
+ """
+ charging: [ChargingStation!]!
+ """
+ Get the meal plan for a specific restaurant
+ """
+ food(locations: [String!]): [Food!]!
+ """
+ Get the campus life events
+ """
+ clEvents: [ClEvent!]!
+ """
+ Get the current bus departures at a specific station
+ """
+ bus(station: String!): [Bus!]!
+ """
+ Get the current train departures at a specific station
+ """
+ train(station: String!): [Train!]!
+ """
+ Get the current announcements
+ """
+ announcements: [Announcement!]!
+}
diff --git a/src/schema/index.ts b/src/schema/index.ts
deleted file mode 100644
index 568cc37..0000000
--- a/src/schema/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { DocumentNode } from 'graphql'
-
-import { queryType } from './query'
-
-export const typeDefs: DocumentNode[] = [queryType]
diff --git a/src/schema/query/announcements.ts b/src/schema/query/announcements.ts
deleted file mode 100644
index f7e670a..0000000
--- a/src/schema/query/announcements.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import gql from 'graphql-tag'
-
-export const announcementsType = gql`
- type Announcement {
- title: MultiLanguageString!
- description: MultiLanguageString!
- startDateTime: String!
- endDateTime: String!
- priority: Int!
- url: String
- }
-
- type MultiLanguageString {
- de: String
- en: String
- }
-`
diff --git a/src/schema/query/bus.ts b/src/schema/query/bus.ts
deleted file mode 100644
index 89c0198..0000000
--- a/src/schema/query/bus.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import gql from 'graphql-tag'
-
-export const busType = gql`
- "Charging station data"
- type Bus {
- route: String!
- destination: String!
- time: String!
- }
-`
diff --git a/src/schema/query/charging.ts b/src/schema/query/charging.ts
deleted file mode 100644
index eb62f7a..0000000
--- a/src/schema/query/charging.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import gql from 'graphql-tag'
-
-export const chargingType = gql`
- "Charging station data"
- type ChargingStation {
- id: Int!
- name: String!
- address: String!
- city: String!
- latitude: Float!
- longitude: Float!
- available: Int!
- total: Int!
- freeParking: Boolean
- operator: String
- }
-`
diff --git a/src/schema/query/cl-events.ts b/src/schema/query/cl-events.ts
deleted file mode 100644
index 7fc5ba8..0000000
--- a/src/schema/query/cl-events.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import gql from 'graphql-tag'
-
-export const clEventsType = gql`
- "Campus Life Event"
- type ClEvent {
- id: ID!
- organizer: String!
- title: String!
- begin: String!
- end: String!
- }
-`
diff --git a/src/schema/query/food.ts b/src/schema/query/food.ts
deleted file mode 100644
index 3558d85..0000000
--- a/src/schema/query/food.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-import gql from 'graphql-tag'
-
-export const foodType = gql`
- "Meal data"
- type Meal {
- name: Name
- id: ID!
- category: String!
- prices: Prices!
- allergens: [String]
- flags: [String]
- nutrition: Nutrition
- variants: [Variation!]
- originalLanguage: OriginalLanguage!
- static: Boolean!
- restaurant: String
- }
-
- "Variants of a meal"
- type Variation {
- name: Name!
- additional: Boolean!
- prices: Prices!
- id: ID!
- allergens: [String]
- flags: [String]
- nutrition: Nutrition
- originalLanguage: OriginalLanguage!
- static: Boolean!
- restaurant: String
- parent: Parent
- variants: [Variation]
- }
-
- "Name of a meal in different languages"
- type Name {
- de: String!
- en: String!
- }
-
- "Nutritional values for a meal"
- type Nutrition {
- kj: Float!
- kcal: Float!
- fat: Float!
- fatSaturated: Float!
- carbs: Float!
- sugar: Float!
- fiber: Float!
- protein: Float!
- salt: Float!
- }
-
- "Original language of the meal name"
- enum OriginalLanguage {
- de
- en
- }
-
- "Prices for different types of customers"
- type Prices {
- student: Float!
- employee: Float!
- guest: Float!
- }
-
- "Provides a list of meals for a specific day"
- type Food {
- timestamp: String!
- meals: [Meal!]
- }
-
- "Parent meal for a variant meal"
- type Parent {
- id: ID!
- category: String!
- name: Name!
- }
-`
diff --git a/src/schema/query/index.ts b/src/schema/query/index.ts
deleted file mode 100644
index 579ce8c..0000000
--- a/src/schema/query/index.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import gql from 'graphql-tag'
-
-import { announcementsType } from './announcements'
-import { busType } from './bus'
-import { chargingType } from './charging'
-import { clEventsType } from './cl-events'
-import { foodType } from './food'
-import { parkingType } from './parking'
-import { trainType } from './train'
-
-export const queryType = gql`
- ${chargingType}
- ${parkingType}
- ${foodType}
- ${clEventsType}
- ${busType}
- ${trainType}
- ${announcementsType}
- "Root query"
- type Query {
- parking: ParkingData
- charging: [ChargingStation!]!
- food(locations: [String!]): [Food!]!
- clEvents: [ClEvent!]!
- bus(station: String!): [Bus!]!
- train(station: String!): [Train!]!
- announcements: [Announcement!]!
- }
-`
diff --git a/src/schema/query/parking.ts b/src/schema/query/parking.ts
deleted file mode 100644
index 6a4fb61..0000000
--- a/src/schema/query/parking.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import gql from 'graphql-tag'
-
-export const parkingType = gql`
- "Parking data"
- type ParkingData {
- updated: String!
- lots: [ParkingLot!]!
- }
-
- "Parking lot data"
- type ParkingLot {
- name: String!
- available: Int!
- priceLevel: Int
- }
-`
diff --git a/src/schema/query/train.ts b/src/schema/query/train.ts
deleted file mode 100644
index 329bb70..0000000
--- a/src/schema/query/train.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import gql from 'graphql-tag'
-
-export const trainType = gql`
- "Train data"
- type Train {
- name: String!
- destination: String!
- plannedTime: String!
- actualTime: String!
- canceled: Boolean!
- track: String
- url: String
- }
-`