Contents

Case Study - PeopleSoft to D2L (Brightspace) Integration

This case study examines a real-world integration between PeopleSoft Campus Solutions and D2L Brightspace (a Learning Management System) using the Valence APIs. This is an outbound integration where PeopleSoft acts as the HTTP client, driving data into D2L. The patterns and lessons here apply to any outbound integration with a modern REST API.

Integration Scope

PeopleSoft was the system of record for student and faculty data. D2L Brightspace was the LMS. The integration needed to keep D2L in sync with PeopleSoft for:

  • User provisioning – Create and update student and faculty accounts in D2L
  • Term creation – Push academic terms to D2L
  • Class/course creation – Create D2L course offerings from the PeopleSoft schedule of classes
  • Student enrollments – Enroll and drop students from courses
  • Faculty assignments – Assign and remove instructors from courses

PeopleSoft was the driver for all of these interactions. D2L was the consumer.

Design Process

Step 1: Understand the API Before Writing Code

Before writing a single line of PeopleCode, every D2L API transaction was tested and documented using HTTP test tools (HTTPYac/Postman). This is critical:

  • Low barrier to entry – no PeopleSoft framework to fight
  • Easy to iterate and discover edge cases
  • Builds a reusable test collection for regression testing later
  • Helps you understand the vendor’s data model and assumptions

Document each API call in HTTP syntax. This becomes your technical specification.

Step 2: Map PeopleSoft Business Transactions to API Calls

Think through every interaction between PeopleSoft and D2L:

  • What PeopleSoft data triggers the interaction?
  • What is the corresponding D2L API call?
  • Is it real-time or batch?
  • How do you cross-reference IDs between systems?
  • What are the edge cases (cancelled classes, name changes, late enrollments)?
  • What is the emergency exit for manual corrections?

Step 3: Design the Code Architecture

The key design principle was separating API complexity from business logic.

Architecture

The integration used a layered architecture:

  ┌─────────────────────────┐
  │  Batch Process / Page   │  ← Knows WHAT data to send
  │  (Driver)               │
  ├─────────────────────────┤
  │  PeopleCode SDK         │  ← Knows HOW to talk to D2L
  │  (Application Package)  │
  ├─────────────────────────┤
  │  D2L Valence API        │  ← HTTP/REST/JSON
  └─────────────────────────┘
  • Driver layer (batch processes and pages): Responsible for selecting the data set and calling the SDK. Knows nothing about HTTP, JSON, or D2L APIs.
  • SDK layer (Application Package classes): Encapsulates all REST/HTTP/JSON logic, authentication, URL construction, logging, rate limiting, and error handling.
  • API layer: The external D2L Valence REST API.

This separation means:

  • Batch processes are simple and focused on data selection
  • The SDK can be reused across multiple batch jobs and pages
  • API changes only require updating the SDK, not every batch process

Class Design

User Service

The user service class handled creating and updating user accounts in D2L.

import MY_D2L_INTEGRATION:user:baseUser;

/* Create an instance for each EMPLID */
Local MY_D2L_INTEGRATION:user:baseUser &d2lUser;
&d2lUser = create MY_D2L_INTEGRATION:user:baseUser(&INSTITUTION, &EMPLID);

If &d2lUser.CreateOrUpdateUser() Then
   /* Success */
Else
   /* Error: check &d2lUser.errorInfo */
End-If;

The batch process does not know anything about D2L URLs, JSON payloads, or authentication. The class handles:

  • Checking if the user already exists in D2L (GET)
  • Comparing PeopleSoft data with D2L data to detect changes
  • Creating new users (POST) or updating existing ones (PUT)
  • Mapping PeopleSoft fields to D2L’s expected JSON format
  • Storing the D2L user ID back in PeopleSoft for cross-referencing

Class/Course Service

import MY_D2L_INTEGRATION:class:classInstance;

Local MY_D2L_INTEGRATION:class:classInstance &c;
&c = create MY_D2L_INTEGRATION:class:classInstance(&INSTITUTION, &STRM, &CLASS_NBR);

If &c.CreateOrUpdate() Then
   /* Course offering created/updated in D2L */
Else
   /* Error: check &c.errorInfo */
End-If;

Enrollment Reconciliation

Enrollment was handled as a reconciliation pattern rather than individual add/drop events:

Local MY_D2L_INTEGRATION:class:classInstance &c;
&c = create MY_D2L_INTEGRATION:class:classInstance(&INSTITUTION, &STRM, &CLASS_NBR);

If &c.existsInCache Then
   /* Reconcile students - compares PeopleSoft enrollments with D2L */
   &c.reconcileStudentEnrollments(&bReportOnly);

   /* Reconcile instructors */
   &c.reconcileInstructorEnrollments(&bReportOnly);
End-If;

The &bReportOnly flag allowed running the reconciliation in “dry run” mode to preview changes before committing them. This was very useful during initial rollout.

Batch Process Scheduling

Different data types had different update frequencies:

Integration Frequency Notes
User provisioning Frequent / near-real-time New users need accounts before classes start
Bio/demo updates Near-real-time Name changes, email updates
Term creation Once per semester Run when term setup is complete
Class creation Frequent during registration window Only when D2L admin setup is ready
Enrollments Frequent during registration Must handle last-minute adds/drops (class starts at 5pm, student enrolled at 4:45pm)

Environment-Aware Configuration

A configuration table stored environment-specific settings, keyed by database name (or institution):

  • API base URL – Different per environment (DEV, TEST, PRD)
  • Authentication credentials – Different per environment
  • Feature flags – Logging verbosity, dry-run mode

This ensures a database refresh from PRD to DEV does not accidentally point DEV at production D2L.

API Interaction Logging

Every outbound API call was logged to a custom PeopleSoft table:

  • Timestamp
  • HTTP method and full URL
  • HTTP status code
  • Response time
  • Request/response body (truncated)
  • Error details

This proved invaluable for:

  • Production support: Quickly diagnosing why a specific user or class failed to sync
  • Detecting vendor changes: When D2L changed API behavior, the logs showed it immediately
  • Usage statistics: Understanding the integration’s API call profile (~85% GET, ~10% POST, ~4% PUT, <1% DELETE)
  • Performance monitoring: Tracking response times and identifying slowdowns

JSON Encoding/Decoding

The integration used PeopleCode’s JsonObject and JsonArray classes for all JSON work. Messages and Document classes were explicitly avoided for outbound integrations because:

  • Modern APIs return variable/dynamic JSON that does not map cleanly to predefined message schemas
  • JsonObject provides direct, flexible access to JSON properties
  • No overhead of maintaining message definitions

See the JSON Encoding and JSON Decoding sections for examples.

Lessons Learned

  1. Test the API thoroughly before writing PeopleCode. Use Postman or HTTPYac to understand every endpoint, error response, and edge case. This saves enormous time.

  2. Separate API logic from business logic. Batch processes should not contain HTTP or JSON code. Put that in an Application Package SDK.

  3. Log everything. You will need the API interaction logs when something goes wrong in production. The time you invest in logging infrastructure pays for itself quickly.

  4. Design for environment isolation. Use configuration tables keyed by database name so DEV never accidentally talks to production APIs.

  5. Plan for certificate maintenance. TLS certificates expire. Set up monitoring and calendar reminders. See the TLS Certificates section for details.

  6. Use %IntBroker.ProvideRestTest for modern REST integrations. The ability to capture HTTP status codes is critical for proper error handling. See PeopleSoft as HTTP Client for the comparison.

  7. Support a “report only” mode. Being able to preview what the integration would do without actually making changes is extremely helpful during rollout and troubleshooting.

  8. Cross-reference IDs between systems. Store the external system’s ID (D2L User ID, D2L Org Unit ID) in PeopleSoft so you can look up records without making extra API calls.


Author Info
Chris Malek

Chris Malek s a PeopleTools® Technical Consultant with over two decades of experience working on PeopleSoft enterprise software projects. He is available for consulting engagements.

Work with Chris