Skip to main content

Tutorial: Interacting with an Ed-Fi API

Audience: developers who wish to learn how to use an Ed-Fi API.

Background assumptions: basic knowledge of REST API semantics and basic familiarity with data exchange standards.

This tutorial will walk through some basic interactions with an Ed-Fi API. It uses a live application running the Ed-Fi Resources API version 5.0 and Descriptors API version 5.0 (hosted via the Ed-Fi ODS/API version 7.1). The concepts are the same in all versions, though some detail of the data models may differ.

note

The data returned by this API may look realistic, but they are entirely fake. The Ed-Fi Alliance does not store, transmit, or have access to student data - we provide software to our community members, who run it for themselves or engage with a partner to do so on their behalf. The live application used by this tutorial is a demonstration site containing synthetic data.

Discovery

Before interacting with an Ed-Fi API, we need to know a few details. First, we need to know the base URL for the running installation. Issuing a GET request to that URL, we receive a document that describes the application with which you are interacting. This endpoint is called the Discovery API.

GET https://api.ed-fi.org/v7.1/api/

In particular, note the following:

  • This application support the Ed-Fi Data Standard 5.0 with Teacher Preparation Data Model (TPDM) extension 1.1.
info

Is it a Standard or a Model? And is it the "Data Standard" or the "API Standard"? It is a little confusing. The "things" (entities) we are describing — such as students, schools, etc. — are defined by the Ed-Fi Data Standard. It enumerates the properties that describe each of those entities. The Data Standard is an abstract concept. We transcribe it into a data model — the Ed-Fi Unifying Data Model (UDM) — that can be used by machines. In the context of a REST API, the UDM becomes a schema prescribing how to encode information about a particular entity. In most scenarios this encoding is in the form of JavaScript Object Notation (JSON).

Back to the questions: from an application code perspective we are now dealing with a standardized API data model. And we have standards around how to employ that data model. Hence, "API Standard". But, since it all flows back to the Ed-Fi Data Standard, it is broadly acceptable to simply refer to the Data Standard.

  • Authentication requests (described in the next section) need to use the URL specified in the $.urls.oauth property.
info

$.urls.oauth is a JSONPath expression; it tells you to start at the top ($) of the document, look for the urls element, then inside of it, look for the value on the oauth element.

Arrays are described in JSONPath using index notation. For example, the TPDM version number is at path $.dataModels[1].version.

  • The $.urls.dataManagementApi provides the base path for access to Ed-Fi Resources and Ed-Fi Descriptors — the entities you are managing via an Ed-Fi API application. The Ed-Fi API Standard defines the complete URL for accessing a resource as the combination of this base URL, a namespace representing the core Ed-Fi UDM ("ed-fi") or an extension (e.g. "tpdm"), and the name of the resource to access. In template form: {$.urls.dataManagementApi}/{extension}/{resource}. If the dataManagementApi value is https://example.com, then the actual URL for accessing Students in the core UDM will be https://example.com/ed-fi/students.

Authentication

All interactions with an Ed-Fi API must be authenticated, generally using the OAuth client credentials flow. The following example submits a pairing of client_id and client_secret, and the response will contain an access_token value. That token value is a temporary key for unlocking access to the Ed-Fi API. What do we mean by "temporary"? Note the expires_in value, which is in milliseconds - the token will expire after this time. If you are not finished with your interactions with the API, then you will need to re-issue the command below to acquire a new token.

POST https://api.ed-fi.org/v7.1/api/oauth/token
Content-Type: application/json

{
"grant_type": "client_credentials",
"client_id": "RvcohKz9zHI4",
"client_secret": "E1iEFusaNf81xzCxwHfbolkC"
}
info

Every API client application will have its own client_id and client_secret. These are alternately called the "key / secret" pair. The application hosting organization provides the key and secret, unique to their installation.

Managing Student Records

Before creating a student, let's retrieve the first student available, for practice. (Why the first? Because otherwise the following request will return 25 results, which would be rather cumbersome in this tutorial!).

We do this with a GET request to the /ed-fi/students endpoint, appending the query string parameters limit=1.

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students?limit=1

Access Token Authorization

Look at the response carefully: it says 401 Unauthorized. We "forgot" to include the access_token from the authentication request! The server does not recognize the client applications and denies it access to this resource.

In the following example, copy the access_token from the response in the Authentication section above into the box below, replacing "98aa86998da3476c95c296e99e397891" after the word "bearer":

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students?limit=1
Authorization: bearer 98aa86998da3476c95c296e99e397891

This time, you should receive status code 200 ("OK") and a response body containing a single student record.

Create a New Student

While there are other elements available on the Student data model, at minimum a Student must have these properties defined: studentUniqueId, birthDate, firstname, lastSurname. The following request creates a new student. Once again, you will need to copy and paste your new access token from above. You might also want to replace the studentUniqueId value with something truly unique; otherwise, if someone else has run this tutorial recently, you will end up updating an existing record instead of creating a new one.

POST https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students
Authorization: bearer 98aa86998da3476c95c296e99e397891
Content-Type: application/json

{
"studentUniqueId": "unique",
"firstName": "Bugs",
"lastSurname": "Bunny",
"birthDate": "1940-07-27"
}

If you have created a new record, then the first line in the response above will have status code 201 ("Created"). If you have updated an existing record, it will be status code 200 ("OK"). Look for the location value in the list of response headers — the key-value pairs below the status code. That location value is the unique URL for the just-created Student. Copy and paste that value into the next request.

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students/692ea2ceebd142bfa7a5ace10c3f11e7
Authorization: bearer 98aa86998da3476c95c296e99e397891

Read that response carefully: you should have received status code 403 ("Forbidden") with a message telling you that authorization was denied!.

Education Organization Authorization

Having an access token is the first step to being authorized to perform an action. The access token provides certain basic permissions, but not blanket permissions. This error tells us that the client_id's permissions do not extend to being able to read this Student. That may sound rather odd, given that we just created the Student in the first place.

info

There are several additional ways of securing student data in the Ed-Fi ODS/API. Most Ed-Fi API applications will have similar rules, but this section is currently specific to the Ed-Fi ODS/API application.

In this case, we are looking at education organization security. Each client_id is assigned to one or more education organizations, most likely a Local Education Agency (LEA) or a specific School. The client application is allowed to allowed to read (or update, or delete) only those Students that are associated with that LEA or individual school. We need to create a studentSchoolAssociation record tying this specific Student to an allowed School. The error message above tells us what educationOrganizationId values we are allowed to use: 255901 or 19255901. But neither of these is a school, as it turns out. We will need a schoolId. The following request looks up the first School associated with LEA 255901.

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/schools?localEducationAgencyId=255901&limit=1
Authorization: bearer 98aa86998da3476c95c296e99e397891

We'll use the schoolId value in the next section.

Creating a Student School Association

The data model for studentSchoolAssociation has only four required properties:

  • schoolReference
  • studentReference
  • entryDate
  • entryGradeLevelDescriptor

These "references" describe other resources that must already exist in the API application. In this case, the reference values are rather simple, both containing only a single property. But, most situations are more complex, due to the multi-part natural keys employed by the Ed-Fi Data Standard. For example, a Section has a five-part natural key; therefore a sectionReference would have five properties in it.

Descriptors are sets of available code values for a given concept. The descriptor value representation in an HTTP request is in the form of a URI with the template {BASE_URI}#{CodeValue}. Entry Grade Level refers to the Grade Level Descriptors. The following example looks up the first two available gradeLevelDescriptor resources held by the API.

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/gradeLevelDescriptors?limit=2
Authorization: bearer 98aa86998da3476c95c296e99e397891

If you update the following request to have a valid bearer token, and the studentUniqueId that you used above, then you should be able to create the association. If the response comes back with status code 201, as expected, then you can try the GET request for the Student again (above). This time, it should be successful.

POST https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/studentSchoolAssociations
Authorization: bearer 000b2ebdc059479d93f75f4f64934dd3
Content-Type: application/json

{
"schoolReference": {
"schoolId": 255901001
},
"studentReference": {
"studentUniqueId": "unique"
},
"entryDate": "2024-06-02",
"entryGradeLevelDescriptor": "uri://ed-fi.org/GradeLevelDescriptor#Ninth grade",
}

Updating the Student

There are two ways to update the student record: with a POST request that contains the natural key (in this case, studentUniqueId), or a PUT request to the specific resource's URL. They are mutually acceptable approaches, and both are shown below. For the PUT request to work, please note that you will need to paste the unique record identifier into the id property, in addition to it being at the end of the URL. But, don't try this on the POST request, because id is not allowed in POST requests.

POST https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students
Authorization: bearer 98aa86998da3476c95c296e99e397891
Content-Type: application/json

{
"studentUniqueId": "unique",
"firstName": "George",
"middleName": "Washington",
"lastSurname": "Bunny",
"birthDate": "1940-07-27"
}
PUT https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students/a597ca255e8e4155b54c389a7b13931c
Authorization: bearer 98aa86998da3476c95c296e99e397891
Content-Type: application/json

{
"id": "a597ca255e8e4155b54c389a7b13931c",
"studentUniqueId": "unique",
"firstName": "George",
"middleName": "Washington",
"lastSurname": "Bunny",
"birthDate": "1940-07-27"
}

Deleting a Resource and Dependency Ordering

To delete the Student, use the same URL as in the PUT request:

DELETE https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/students/a597ca255e8e4155b54c389a7b13931c
Authorization: bearer 98aa86998da3476c95c296e99e397891

Look carefully: the request should have failed with status code 409 ("Conflict"). The detail error message tells you that there is a Student School Association connected to this Student, and therefore it cannot be deleted. This is an example of the Ed-Fi API's referential integrity in action. If you were allowed to delete this Student, then there would be a dangling Student School Association that points to a student who does not exist!

This is an example of dependency ordering. Look again at the Discovery API example at the top of this page. The URL specified at path $.urls.dependencies can be used to help understand dependency order. For example, /ed-fi/students has order 3, and /ed-fi/studentSchoolAssociations has order 13. When creating a resource, the lower number must be created first. When deleting, we must go in reverse: delete the higher number first.

To delete the Student School Association, you will need the id value to insert into the URL. The following GET will return the studentSchoolAssociation record, from which the id value can be copied and pasted into the DELETE request that follows it.

GET https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/studentSchoolAssociations?studentUniqueId=unique&schoolId=255901001
Authorization: bearer 98aa86998da3476c95c296e99e397891
DELETE https://api.ed-fi.org/v7.1/api/data/v3/ed-fi/studentSchoolAssociations/629d690e8007483ba52780749688f104
Authorization: bearer 98aa86998da3476c95c296e99e397891

Finally, try the the DELETE /ed-fi/students request above again. A successful DELETE request will result in a 204 status code ("No Content").

Exploring the Full Ed-Fi Resources API

In this tutorial, you have learned the basics of how to create, read, update, and delete ("CRUD") data in an Ed-Fi API, have learned the basics about authorization, and have seen specific examples relating to Students, Grade Level Descriptors, and Student School Associations.

As a next step in learning how to interact with an Ed-Fi API, we suggest trying the live documentation site for ODS/API 7.1. It uses a tool called Swagger UI to read the OpenAPI specification file — provided by the Discovery API, in $.urls.openApiMetadata — and create a friendly user interface for exploring the full scope of the Resources API.

A few tips to help you navigate and use the tool:

  1. The "Authorize" button at the top, or the small lock icons on each request, facilitates client authentication for acquiring an access token. The tool will automatically apply that access token for you, so that you don't need to copy and paste it as you did in this tutorial.
  2. Click the down arrow on the right side of the page to expand a section.
  3. Each resource type (e.g. academicWeeks, accountabilityRatings, etc.) has expandable content for GET, POST, GET by ID, PUT, and DELETE requests — plus two more GET requests that relate to the Change Queries feature.
  4. The GET request shows all of the available query string parameters for filtering query results.
  5. The POST request shows an example value by default. Click on the word Schema above the example value to learn more about the data model for that resource type. This data model shows you all of the properties available for that resource, and it places a red asterisk next to all of the required properties.
  6. At the top of the page there is a dropdown menu that will allow you to explore Ed-Fi API definitions other than the Resource API. For example, you can explore the Descriptors API.

Further Reading

The following resources will help you learn more about working with an Ed-Fi API application:

  • Ed-Fi API Guidelines: this space contains guidance on how to build a compliant Ed-Fi API application. Those who are writing client applications that interact with a compatible Ed-Fi API application can also benefit by learning more about what to expect from the system.
  • API Client Developers' Guide: provides more detail on many of the topics explored in this tutorial, and covers additional details not reviewed here. This link is to the Ed-fFi ODS/API version 7.1 documentation. Most if not all content there applies equally to other versions of the Ed-Fi ODS/API and to other Ed-Fi API applications more generally.