Erste Schritte mit Bewertungsschemas

Ein rubric ist eine Vorlage, die Lehrkräfte zum Bewerten von Schüleraufgaben verwenden können. Mit der Classroom API können Sie im Namen des Lehrers diese Rubriken verwalten und Rubriknoten für Schüler-/Studentenaufgaben lesen.

Ansicht eines Bewertungsschemas in der Classroom-BenutzeroberflächeAbbildung 1. Beispiel für ein Bewertungsschema für eine Classroom-Aufgabe.

In diesem Leitfaden werden die grundlegenden Konzepte und Funktionen der Rubrics API erläutert. In diesen Hilfeartikeln finden Sie Informationen zur allgemeinen Struktur einer Rubrik und dazu, wie die Bewertung mit Rubriken in der Classroom-Benutzeroberfläche erfolgt.

Vorbereitung

In diesem Leitfaden wird davon ausgegangen, dass Sie Folgendes haben:

Anmeldedaten für eine Desktopanwendung autorisieren

Für die Authentifizierung als Endnutzer und für den Zugriff auf Nutzerdaten in Ihrer Anwendung müssen Sie mindestens eine OAuth 2.0-Client-ID erstellen. Eine Client-ID wird zur Identifizierung einer einzelnen Anwendung bei Googles OAuth-Servern verwendet. Wenn Ihre App auf mehreren Plattformen ausgeführt wird, müssen Sie für jede Plattform eine separate Client-ID erstellen.

  1. Rufen Sie in der Google Cloud Console die Seite „Anmeldedaten“ auf.
  2. Klicken Sie auf Anmeldedaten erstellen > OAuth-Client-ID.
  3. Klicken Sie auf Anwendungstyp > Desktop-App.
  4. Geben Sie im Feld Name einen Namen für die Anmeldedaten ein. Dieser Name wird nur in der Google Cloud Console angezeigt. Beispiel: „Rubrics client“.
  5. Klicken Sie auf Erstellen. Der Bildschirm „OAuth-Client erstellt“ wird angezeigt und enthält Ihre neue Client-ID und Ihren neuen Clientschlüssel.
  6. Klicken Sie auf JSON herunterladen und dann auf OK. Die neu erstellten Anmeldedaten werden unter „OAuth 2.0 Client IDs“ (OAuth 2.0-Client-IDs) angezeigt.
  7. Speichern Sie die heruntergeladene JSON-Datei als credentials.json und verschieben Sie sie in Ihr Arbeitsverzeichnis.
  8. Klicken Sie auf Anmeldedaten erstellen > API-Schlüssel und notieren Sie sich den API-Schlüssel.

Weitere Informationen finden Sie unter Anmeldedaten für den Zugriff erstellen.

OAuth-Bereiche konfigurieren

Je nach den vorhandenen OAuth-Bereichen Ihres Projekts müssen Sie möglicherweise zusätzliche Bereiche konfigurieren.

  1. Rufen Sie den OAuth-Zustimmungsbildschirm auf.
  2. Klicken Sie auf App bearbeiten > Speichern und fortfahren, um zum Bildschirm „Bereiche“ zu gelangen.
  3. Klicken Sie auf Bereiche hinzufügen oder entfernen.
  4. Fügen Sie die folgenden Bereiche hinzu, falls Sie sie noch nicht haben:
    • https://www.googleapis.com/auth/classroom.coursework.students
    • https://www.googleapis.com/auth/classroom.courses
  5. Klicken Sie dann auf Aktualisieren > Speichern und fortfahren > Speichern und fortfahren > Zurück zum Dashboard.

Weitere Informationen finden Sie unter OAuth-Zustimmungsbildschirm konfigurieren.

Der Bereich classroom.coursework.students ermöglicht Lese- und Schreibzugriff auf Rubriken (zusammen mit Zugriff auf CourseWork), und der Bereich classroom.courses ermöglicht das Lesen und Schreiben von Kursen.

Die für eine bestimmte Methode erforderlichen Bereiche sind in der Referenzdokumentation für die Methode aufgeführt. Ein Beispiel finden Sie unter courses.courseWork.rubrics.create-Autorisierungsbereiche. Alle Classroom-Bereiche finden Sie unter OAuth 2.0-Bereiche für Google APIs.

Beispiel konfigurieren

Installieren Sie im Arbeitsverzeichnis die Google-Clientbibliothek für Python:

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

Erstellen Sie eine Datei mit dem Namen main.py, die die Clientbibliothek erstellt und den Nutzer autorisiert. Verwenden Sie dabei Ihren API-Schlüssel anstelle von YOUR_API_KEY:

import json
import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/classroom.courses',
          'https://www.googleapis.com/auth/classroom.coursework.students']

def build_authenticated_service(api_key):
    """Builds the Classroom service."""
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run.
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        # Build the Classroom service.
        service = build(
            serviceName="classroom",
            version="v1",
            credentials=creds,
            discoveryServiceUrl=f"https://classroom.googleapis.com/$discovery/rest?labels=DEVELOPER_PREVIEW&key={api_key}")

        return service

    except HttpError as error:
        print('An error occurred: %s' % error)

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

Führen Sie das Skript mit python main.py aus. Sie sollten aufgefordert werden, sich anzumelden und OAuth-Bereichen zuzustimmen.

Zuweisung erstellen

Eine Rubrik ist einer Aufgabe oder CourseWork zugeordnet und ist nur im Kontext dieser CourseWork sinnvoll. Rubriken können nur von dem Google Cloud-Projekt erstellt werden, mit dem das übergeordnete CourseWork-Element erstellt wurde. Erstellen Sie für diese Anleitung eine neue CourseWork-Zuweisung mit einem Script.

Fügen Sie main.py Folgendes hinzu:

def get_latest_course(service):
    """Retrieves the last created course."""
    try:
        response = service.courses().list(pageSize=1).execute()
        courses = response.get("courses", [])
        if not courses:
            print("No courses found. Did you remember to create one in the UI?")
            return
        course = courses[0]
        return course

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

def create_coursework(service, course_id):
    """Creates and returns a sample coursework."""
    try:
        coursework = {
            "title": "Romeo and Juliet analysis.",
            "description": """Write a paper arguing that Romeo and Juliet were
                                time travelers from the future.""",
            "workType": "ASSIGNMENT",
            "state": "PUBLISHED",
        }
        coursework = service.courses().courseWork().create(
            courseId=course_id, body=coursework).execute()
        return coursework

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Aktualisieren Sie nun main.py, um die course_id der Testklasse abzurufen, die Sie gerade erstellt haben. Erstellen Sie dann eine neue Beispielzuweisung und rufen Sie die coursework_id der Zuweisung ab:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    course = get_latest_course(service)
    course_id = course.get("id")
    course_name = course.get("name")
    print(f"'{course_name}' course ID: {course_id}")

    coursework = create_coursework(service, course_id)
    coursework_id = coursework.get("id")
    print(f"Assignment created with ID {coursework_id}")

    #TODO(developer): Save the printed course and coursework IDs.

Speichere die course_id und coursework_id. Sie sind für alle CRUD-Vorgänge für Rubriken erforderlich.

Sie sollten jetzt eine Beispielaufgabe CourseWork in Classroom haben.

Ansicht einer Aufgabe in der Classroom-BenutzeroberflächeAbbildung 2. Ansicht einer Beispielaufgabe in Classroom

Nutzerberechtigung prüfen

Zum Erstellen und Aktualisieren von Rubriken müssen sowohl der Nutzer, der die Anfrage stellt, als auch der entsprechende Kursinhaber eine Google Workspace for Education Plus-Lizenz haben. Classroom unterstützt einen Berechtigungs-Endpunkt, mit dem Entwickler die Funktionen ermitteln können, auf die ein Nutzer Zugriff hat.

Aktualisieren Sie main.py und führen Sie es aus, um zu bestätigen, dass Ihr Testkonto Zugriff auf die Funktion für die Erstellung von Rubriken hat:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
      print('User eligible for rubrics creation.')

Bewertungsschema erstellen

Jetzt können Sie mit der Verwaltung von Rubriken beginnen.

Ein Bewertungsschema kann für ein CourseWork mit einem create()-Aufruf erstellt werden, der das vollständige Bewertungsschema-Objekt enthält. Die ID-Properties für Kriterien und Stufen werden dabei ausgelassen, da sie bei der Erstellung generiert werden.

Fügen Sie main.py die folgende Funktion hinzu:

def create_rubric(service, course_id, coursework_id):
    """Creates an example rubric on a coursework."""
    try:
        body = {
            "criteria": [
                {
                    "title": "Argument",
                    "description": "How well structured your argument is.",
                    "levels": [
                        {"title": "Convincing",
                         "description": "A compelling case is made.", "points": 30},
                        {"title": "Passable",
                         "description": "Missing some evidence.", "points": 20},
                        {"title": "Needs Work",
                         "description": "Not enough strong evidence..", "points": 0},
                    ]
                },
                {
                    "title": "Spelling",
                    "description": "How well you spelled all the words.",
                    "levels": [
                        {"title": "Perfect",
                         "description": "No mistakes.", "points": 20},
                        {"title": "Great",
                         "description": "A mistake or two.", "points": 15},
                        {"title": "Needs Work",
                         "description": "Many mistakes.", "points": 5},
                    ]
                },
                {
                    "title": "Grammar",
                    "description": "How grammatically correct your sentences are.",
                    "levels": [
                        {"title": "Perfect",
                         "description": "No mistakes.", "points": 20},
                        {"title": "Great",
                         "description": "A mistake or two.", "points": 15},
                        {"title": "Needs Work",
                         "description": "Many mistakes.", "points": 5},
                    ]
                },
            ]
        }

        rubric = service.courses().courseWork().rubrics().create(
            courseId=course_id, courseWorkId=coursework_id, body=body
            ).execute()
        print(f"Rubric created with ID {rubric.get('id')}")
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Aktualisieren Sie dann main.py und führen Sie es aus, um die Beispielrubrik zu erstellen. Verwenden Sie dazu Ihre Course- und CourseWork-IDs von oben:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
      rubric = create_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
      print(json.dumps(rubric, indent=4))

Einige Hinweise zur Darstellung der Rubrik:

  • Die Reihenfolge der Kriterien und Stufen wird in der Classroom-Benutzeroberfläche berücksichtigt.
  • Ebenen mit Punktzahlen (mit dem Attribut points) müssen nach Punkten in aufsteigender oder absteigender Reihenfolge sortiert werden. Eine zufällige Sortierung ist nicht möglich.
  • Lehrkräfte können Kriterien und bewertete Niveaus (aber nicht unbewertete Niveaus) in der Benutzeroberfläche neu sortieren. Dadurch ändert sich ihre Reihenfolge in den Daten.

Weitere Hinweise zur Struktur von Rubriken finden Sie unter Einschränkungen.

Zurück in der Benutzeroberfläche sollte die Rubrik in der Aufgabe angezeigt werden.

Ansicht eines Bewertungsschemas in der Classroom-Benutzeroberfläche Abbildung 3: Beispiel für ein Bewertungsschema für eine Classroom-Aufgabe.

Bewertungsschema lesen

Rubriken können mit den Standardmethoden list() und get() gelesen werden.

Eine Aufgabe kann höchstens eine Rubrik enthalten. Daher mag list() nicht intuitiv erscheinen, ist aber hilfreich, wenn Sie die Rubrik-ID noch nicht haben. Wenn kein Rubrik mit einem CourseWork verknüpft ist, ist die list()-Antwort leer.

Fügen Sie main.py die folgende Funktion hinzu:

def get_rubric(service, course_id, coursework_id):
    """
    Get the rubric on a coursework. There can only be at most one.
    Returns null if there is no rubric.
    """
    try:
        response = service.courses().courseWork().rubrics().list(
            courseId=course_id, courseWorkId=coursework_id
            ).execute()

        rubrics = response.get("rubrics", [])
        if not rubrics:
            print("No rubric found for this assignment.")
            return
        rubric = rubrics[0]
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Aktualisieren Sie main.py und führen Sie es aus, um das hinzugefügte Bewertungsschema abzurufen:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    print(json.dumps(rubric, indent=4))

    #TODO(developer): Save the printed rubric ID.

Notieren Sie sich das Attribut id in der Rubrik für spätere Schritte.

Get() funktioniert gut, wenn Sie die Rubrik-ID haben. Wenn Sie stattdessen get() in der Funktion verwenden, sieht das so aus:

def get_rubric(service, course_id, coursework_id, rubric_id):
    """
    Get the rubric on a coursework. There can only be at most one.
    Returns a 404 if there is no rubric.
    """
    try:
        rubric = service.courses().courseWork().rubrics().get(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id
        ).execute()

        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Diese Implementierung gibt den Fehlercode 404 zurück, wenn kein Rubrik vorhanden ist.

Bewertungsschema aktualisieren

Aktualisierungen einer Rubrik erfolgen mit patch()-Aufrufen. Aufgrund der komplexen Struktur einer Rubrik müssen Aktualisierungen mit einem Read-Modify-Write-Muster erfolgen, bei dem die gesamte criteria-Eigenschaft ersetzt wird.

Die Aktualisierungsregeln sind:

  1. Kriterien oder Ebenen, die ohne ID hinzugefügt werden, gelten als Ergänzungen.
  2. Kriterien oder Stufen, die zuvor nicht vorhanden waren, gelten als Löschungen.
  3. Kriterien oder Ebenen mit einer vorhandenen ID, aber geänderten Daten werden als Bearbeitungen betrachtet. Unveränderte Attribute bleiben unverändert.
  4. Kriterien oder Ebenen, die mit neuen oder unbekannten IDs angegeben werden, gelten als Fehler.
  5. Die Reihenfolge der neuen Kriterien und Stufen entspricht der neuen Reihenfolge auf der Benutzeroberfläche (mit den oben genannten Einschränkungen).

Fügen Sie eine Funktion zum Aktualisieren eines Bewertungsschemas hinzu:

def update_rubric(service, course_id, coursework_id, rubric_id, body):
    """
    Updates the rubric on a coursework.
    """
    try:
        rubric = service.courses().courseWork().rubrics().patch(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id,
            body=body,
            updateMask='criteria'
        ).execute()

        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

In diesem Beispiel wird das Feld criteria für die Änderung mit einem updateMask angegeben.

Ändern Sie dann main.py, um eine Änderung für jede der oben genannten Aktualisierungsregeln vorzunehmen:

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    capability = service.userProfiles().checkUserCapability(
        userId='me',
        # Specify the preview version. checkUserCapability is
        # supported in V1_20240930_PREVIEW and later.
        previewVersion="V1_20240930_PREVIEW",
        capability="CREATE_RUBRIC").execute()

    if not capability.get('allowed'):
      print('User ineligible for rubrics creation.')
      # TODO(developer): in a production app, this signal could be used to
      # proactively hide any rubrics related features from users or encourage
      # them to upgrade to the appropriate license.
    else:
        # Get the latest rubric.
        rubric = get_rubric(service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
        criteria = rubric.get("criteria")
        """
        The "criteria" property should look like this:
        [
            {
                "id": "NkEyMdMyMzM2Nxkw",
                "title": "Argument",
                "description": "How well structured your argument is.",
                "levels": [
                    {
                        "id": "NkEyMdMyMzM2Nxkx",
                        "title": "Convincing",
                        "description": "A compelling case is made.",
                        "points": 30
                    },
                    {
                        "id": "NkEyMdMyMzM2Nxky",
                        "title": "Passable",
                        "description": "Missing some evidence.",
                        "points": 20
                    },
                    {
                        "id": "NkEyMdMyMzM2Nxkz",
                        "title": "Needs Work",
                        "description": "Not enough strong evidence..",
                        "points": 0
                    }
                ]
            },
            {
                "id": "NkEyMdMyMzM2Nxk0",
                "title": "Spelling",
                "description": "How well you spelled all the words.",
                "levels": [...]
            },
            {
                "id": "NkEyMdMyMzM2Nxk4",
                "title": "Grammar",
                "description": "How grammatically correct your sentences are.",
                "levels": [...]
            }
        ]
        """

        # Make edits. This example will make one of each type of change.

        # Add a new level to the first criteria. Levels must remain sorted by
        # points.
        new_level = {
            "title": "Profound",
            "description": "Truly unique insight.",
            "points": 50
        }
        criteria[0]["levels"].insert(0, new_level)

        # Remove the last criteria.
        del criteria[-1]

        # Update the criteria titles with numeric prefixes.
        for index, criterion in enumerate(criteria):
            criterion["title"] = f"{index}: {criterion['title']}"

        # Resort the levels from descending to ascending points.
        for criterion in criteria:
            criterion["levels"].sort(key=lambda level: level["points"])

        # Update the rubric with a patch call.
        new_rubric = update_rubric(
            service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID, YOUR_RUBRIC_ID, rubric)

        print(json.dumps(new_rubric, indent=4))

Die Änderungen sollten jetzt für die Lehrkraft in Classroom angezeigt werden.

Aktualisiertes Bewertungsschema in der Classroom-Benutzeroberfläche Abbildung 4: Ansicht der aktualisierten Rubrik.

Anhand von Bewertungsschema benotete Aufgaben ansehen

Derzeit können Schüler-/Studentenaufgaben nicht über die API anhand eines Bewertungsschemas benotet werden. Sie können jedoch Noten für Aufgaben, die in der Classroom-Benutzeroberfläche anhand eines Bewertungsschemas benotet wurden, über die API abrufen.

Als Schüler bzw. Student müssen Sie in der Classroom-Benutzeroberfläche die Beispielaufgabe erledigen und abgeben. Als Lehrkraft können Sie die Aufgabe dann manuell anhand des Bewertungsschemas benoten.

Ansicht einer Bewertungsschema-Note in der Classroom-Benutzeroberfläche Abbildung 5: Ansicht des Bewertungsschemas für Lehrkräfte während der Benotung.

StudentSubmissions, die mit einer Rubrik benotet wurden, haben zwei neue Attribute: draftRubricGrades und assignedRubricGrades. Sie stehen für die Punkte und Stufen, die von der Lehrkraft während des Entwurfs und der zugewiesenen Benotungsstatus ausgewählt wurden.

Sie können die vorhandenen Methoden studentSubmissions.get() und studentSubmissions.list() verwenden, um bewertete Aufgaben anzusehen.

Fügen Sie main.py die folgende Funktion hinzu, um die von Schülern eingereichten Aufgaben aufzulisten:

def get_latest_submission(service, course_id, coursework_id):
    """Retrieves the last submission for an assignment."""
    try:
        response = service.courses().courseWork().studentSubmissions().list(
            courseId = course_id,
            courseWorkId = coursework_id,
            pageSize=1
        ).execute()
        submissions = response.get("studentSubmissions", [])
        if not submissions:
            print(
                """No submissions found. Did you remember to turn in and grade
                   the assignment in the UI?""")
            return
        submission = submissions[0]
        return submission

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Aktualisieren Sie dann main.py und führen Sie es aus, um die Noten für die Einsendung zu sehen.

if __name__ == '__main__':
    service = build_authenticated_service(YOUR_API_KEY)

    submission = get_latest_submission(
        service, YOUR_COURSE_ID, YOUR_COURSEWORK_ID)
    print(json.dumps(submission, indent=4))

draftRubricGrades und assignedRubricGrades enthalten Folgendes:

  • Die criterionId der entsprechenden Rubrikkriterien.
  • Die points, die der Lehrer für jedes Kriterium zugewiesen hat. Das kann am ausgewählten Niveau liegen, aber die Lehrkraft kann diese Einstellung auch überschrieben haben.
  • Die levelId der für jedes Kriterium ausgewählten Stufe. Wenn die Lehrkraft kein Niveau ausgewählt, aber trotzdem Punkte für das Kriterium zugewiesen hat, ist dieses Feld nicht vorhanden.

Diese Listen enthalten nur Einträge für die Kriterien, bei denen ein Kursleiter entweder eine Stufe ausgewählt oder Punkte festgelegt hat. Wenn eine Lehrkraft beispielsweise nur ein Kriterium für die Benotung auswählt, enthalten draftRubricGrades und assignedRubricGrades nur ein Element, auch wenn die Rubrik viele Kriterien hat.

Bewertungsschema löschen

Eine Rubrik kann mit einer standardmäßigen delete()-Anfrage gelöscht werden. Der folgende Code zeigt eine Beispiel-Funktion zur Vollständigkeit. Da die Bewertung jedoch bereits begonnen hat, können Sie die aktuelle Rubrik nicht löschen:

def delete_rubric(service, course_id, coursework_id, rubric_id):
    """Deletes the rubric on a coursework."""
    try:
        service.courses().courseWork().rubrics().delete(
            courseId=course_id,
            courseWorkId=coursework_id,
            id=rubric_id
        ).execute()

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error

Rubriken exportieren und importieren

Bewertungsschemas können manuell in Google Tabellen exportiert werden, damit Lehrkräfte sie wiederverwenden können.

Neben der Angabe von Bewertungsschema-Kriterien im Code ist es auch möglich, Bewertungsschemas aus diesen exportierten Tabellen zu erstellen und zu aktualisieren. Dazu müssen Sie sourceSpreadsheetId anstelle von criteria im Hauptteil des Bewertungsschemas angeben:

def create_rubric_from_sheet(service, course_id, coursework_id, sheet_id):
    """Creates an example rubric on a coursework."""
    try:
        body = {
            "sourceSpreadsheetId": sheet_id
        }

        rubric = service.courses().courseWork().rubrics().create(
            courseId=course_id, courseWorkId=coursework_id, body=body
            ).execute()

        print(f"Rubric created with ID {rubric.get('id')}")
        return rubric

    except HttpError as error:
        print(f"An error occurred: {error}")
        return error