Bug when updating quizzes?

I'm an experienced developper making a tool to update a bunch of information programatically. I have no problem updating folders but I have a weird issue with the PUT /quizzes/quizID endpoint, see here https://docs.valence.desire2learn.com/res/quiz.html#put--d2l-api-le-(version)-(orgUnitId)-quizzes-(quizId)

I kinda figured that the output of the GET version would be valid in the PUT but according to the documentation it looks like the 2 formats are ever so slightly different.

Now I looked over my request body dozens of time and I cannot for the life of me figure out why the API is returning

{"type":"http://docs.valence.desire2learn.com/res/apiprop.html#json-binding-error","title":"JSON Binding Error","status":400,"detail":"Provided JSON is invalid or does not match the expected format."}

If anyone can figure out what about my payload is wrong (or if the API has a bug) that's be greatly appreciated.

gist to my payload:

It is worth nothing that I first get the quiz from /quizzes/quizId and then apply the following transformation in order to try and match what the d2l documentation says about the body of a PUT request for updating quizzes:

- delete QuizId (does not appear in the documentation)
- delete AttemptsAllowed (same)
- delete ActivityId (same)
- set NumberOfAttemptsAllowed to old.AttemptsAllowed.NumberOfAttemptsAllowed (the documentation refers to that information differently between the GET response and PUT body)
- set Password to "" (It's null from the GET and the PUT body documentation specifically says the password cannot be null, but also says it cannot be an empty string. null or empty string it doesn't work)
- set NotificationEmail to "" (It's null from the GET and the PUT body documentation says it must be a string)
- set RestrictIPAddressRange to [] (It comes back as an empty array so I figured I'd try something.)

The only information I'm trying to change is the start/due/end date. Everything else is the same.

Can anybody spot my mistake?


  • brad.r.503
    brad.r.503 Posts: 35

    The error you're encountering, "Provided JSON is invalid or does not match the expected format," suggests there is a mismatch between the structure or content of your JSON payload and what the API endpoint expects. Here are a few suggestions and things to check based on the transformations you're applying and the issue you're facing:

    1. Field Deletion:
      • You mentioned deleting QuizId, AttemptsAllowed, and ActivityId as they do not appear in the PUT request documentation. Ensure these fields are indeed not required by the PUT endpoint. Sometimes, documentation might omit certain fields, assuming they are understood to be required or optional based on context or convention.
    2. Attempts Allowed:
      • You are transforming old.AttemptsAllowed.NumberOfAttemptsAllowed to NumberOfAttemptsAllowed. Double-check if the API expects NumberOfAttemptsAllowed directly or if it should be nested inside another object or structure.
    3. Password Field:
      • The API specifies that the password cannot be null and cannot be an empty string. This is a bit contradictory since these are usually the two ways to represent "no password." You might want to try sending a dummy password, like a space " " or some random string, and see if that is accepted. If it works, it might not be the ideal solution, but it can be a temporary workaround until you get clarification on this behavior.
    4. NotificationEmail Field:
      • Similar to the password, if the documentation says it must be a string and cannot be null, setting it to an empty string "" is generally the right approach. However, if this doesn't work, you might consider putting in a dummy email or your own email to test if it accepts that.
    5. RestrictIPAddressRange:
      • Setting RestrictIPAddressRange to an empty array [] seems correct if the API documentation doesn't specify otherwise. Ensure that this field is indeed expected to be an array and that having an empty array is valid.
    6. Date Fields:
      • Since you're trying to change start/due/end dates, make sure the format of the dates matches exactly what the API expects. Date format issues are a common source of API errors. The required format can sometimes be ISO 8601 or another specific format.
    7. Validation Against Schema:
      • If you have access to the JSON schema or a precise documentation of the expected structure, validate your JSON against that schema. There are online tools available for JSON validation against a schema, which can help pinpoint structural issues.
    8. Check for Unintended Null Values:
      • Ensure that your transformation process isn't introducing null values or removing necessary fields unintentionally.
    9. API Version and Endpoint Consistency:
      • Ensure that you're hitting the correct version of the API. Sometimes, APIs have versioned paths, and behavior can differ significantly between versions.
    10. Contact API Support:
      • If you've double-checked everything and it still doesn't work, consider reaching out to the API support team. Sometimes the issue might be on the backend, or the documentation might be outdated or missing crucial information.

    In debugging such issues, it can also be helpful to use tools like Postman or Curl to manually craft requests. This way, you can isolate the problem away from your code logic and transformations.

  • Olivier.G.532
    Olivier.G.532 Posts: 19 🌱
    edited February 7

    How do I contact the API support team?

  • Olivier.G.532
    Olivier.G.532 Posts: 19 🌱
    edited February 8
  • Stefanie.B.518
    Stefanie.B.518 Posts: 468 admin
    edited February 9

    I'm connecting with some of our API SMEs here at D2L to provide you an update.

  • Viktor.H.147

    This seems like it could be a fairly classic gotcha with the Brightspace APIs.

    With a lot of the APIs, when you read an entity from Brightspace user-visible-text fields get encoded as RichText structures. However, when you write to create or update that entity into Brightspace, often you need to encode those fields as RichTextInput structures. The particular Quiz API structures here use that pattern, I believe (QuizReadData for read, QuizData for write).

    You may find that making this adjustment to your call addresses the issue.

  • Olivier.G.532
    Olivier.G.532 Posts: 19 🌱
    edited February 9

    @Viktor.H.147 Ah yes you found it. That is a gotcha. Can we log a couple bugs though? Like e.g. the API says that Quiz password cannot be null but it can and it indicated no password.

    Thanks you for your help. I was able to finish my tool https://hydroflame.github.io/brightspace-assistant/ (no I can't get an approved app from Algonquin College so I have to do the token shenanigan)

  • Viktor.H.147

    If you post the documentation inconsistencies here, I can see that they're followed up on. If the real cause of the inconsistency turns out to be an implementation problem, we'll likely need a support case; but if the error is on the documentation end of things, we can get that done without the effort of a support case.

  • Olivier.G.532
    Olivier.G.532 Posts: 19 🌱
    edited February 9

    Both of these fields from QuizData are marked as required string in the documentation despite the API accepting null for various reasons. QuizReadData also says they cannot be null but will sometimes come back as such.

    Additionally QuizReadData says RestrictedIPRange will not be null but it can.

    It's also confusing that POST /folders/{folderId} accepts RichText without transformation from the GET endpoint, which is why I initially didn't transform it for quizzes. But I guess that's nice? So if quizzes could also accept RichText that's be cool.

  • Viktor.H.147

    Yes, sadly the pattern of "RichText on read, RichTextInput on input" is not entirely consistent. Thanks for your report!