zooniverse / education-api

Backend for Zooniverse Classrooms
1 stars 1 forks source link

[WIP] API Guide for Front-End Developers #44

Open shaunanoordin opened 7 years ago

shaunanoordin commented 7 years ago

Zooniverse Education API

A front-end dev's reverse-engineering of the Zoo EduAPI endpoints, as used by WildCam (Gorongosa) Lab.

This is only a WIP and will be turned into a proper README-like guide/API documentation once completed.

Please feel free to edit/contribute/correct, especially if you know more about the eldritch magicks of Ruby and can simply read the repo code.

Basic Setup

The Education API follows the standard JSON API 1.0 rules. API requests need to have some Zooniverse/Panoptes authorisation code in their request headers - fortunately, this is easily done using the Panoptes JavaScript client.

Example code, using fetch():

import apiClient from 'panoptes-client/lib/api-client';
import fetch from 'isomorphic-fetch';  //The isomorphic-fetch library will save you headaches when handling IE11. Or use a non-fetch alternative.

fetch(root + assignments, {
  method: 'POST',
  mode: 'cors',
  headers: new Headers({
    'Authorization': apiClient.headers.Authorization,  //Get your Auth code
    'Content-Type': 'application/json'
  }), 
  body: JSON.stringify({  //REMINDER: Transform into a string!
    "data": {
      "attributes": { "name": "TEST" }
    }
  })
})
.then(response => response.json())
.then(json => { ...(yadda yadda)... });

Example Request header will look like...

POST /teachers/classrooms/ HTTP/1.1
Host: education-api.zooniverse.org
Connection: keep-alive
Content-Length: 81
Pragma: no-cache
Cache-Control: no-cache
User-Agent: ...(yadda yadda)...
Origin: http://localhost:3000
authorization: ...(yadda yadda)...
content-type: application/json
Accept: */*
Referer: http://localhost:3000/teachers/classrooms/new
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8

WARNING (2017.08.07)

While this document was being written, we had a bit of a quirk where certain item key names use - dashes instead of the intended _ underscores.

For example, you might see some Response bodies replying with join-token instead of join_token - join_token is the correct one. Please adjust your code accordingly once this quirk has been fixed.

Programs

A program is a database representation of a curricula associated with a Zooniverse project or many projects. Generally, there are two "types" of programs: Wildcam style and Intro2Astro style. The type is indicated by the custom boolean property on the program resource.

Wildcam style programs have custom: true set, meaning:

Intro2Astro style programs have custom: false set, meaning:

Classrooms and Programs relationship

GET programs

Request

GET https://education-api.zooniverse.org/programs

Response (Success)

200 OK

Body:

{
  "data": [
    {
      "id": "1",
      "type": "programs",
      "attributes": {
        "slug": "astro-101-with-galaxy-zoo",
        "name": "Astro 101 with Galaxy Zoo",
        "metadata": {
          "cardImage": "home-card-intro-to-astro.jpg",
          "assignments": {
            "2218": {
              "name": "Hubble's Law",
              "slug": "srallen086/intro2astro-hubble-testing",
              "classifications_target": "10"
            },
            "3037": {
              "name": "Galaxy Zoo 101",
              "slug": "srallen086/galaxy-zoo-in-astronomy-101",
              "classifications_target": "22"
              }
            },
            "redirectOnJoin": false,
            "backgroundImage": "astro-background.jpg"
          },
        "description": "Materials and tools for engaging introductory astronomy students in real research with Galaxy Zoo.",
        "custom": false
      }
    }, 
    {
      "id": "2",
      "type": "programs",
      "attributes": {
        "slug": "wildcam-darien-lab",
        "name": "Wildcam Darien Lab",
        "metadata": {
          "cardImage": "home-card-wildcam-darien.jpg",
          "workflowId": "3116",
          "redirectOnJoin":true,
          "sampleSubjects": ["73437","73438","73434"],
          "backgroundImage": ""
        },
        "description": "A map for exploring camera trap data from the WildCam Darien project.",
        "custom": true
      }
    }, {
      "id": "4",
      "type": "programs",
      "attributes": {
        "slug": "wildcam-gorongosa-lab",
        "name": "Wildcam Gorongosa Lab",
        "metadata": {
          "redirect": "https://lab.wildcamgorongosa.org/",
          "cardImage": "gorongosa-animals.jpg",
          "workflowId": "1549",
          "sampleSubjects": ["37763","37755","37767"]
        },
        "description": "A map for exploring camera trap data from the WildCam Gorongosa project.",
        "custom": true
      }
    }
  ]
}

The API currently does not support other CRUD actions yet for programs. If a new program needs to be created or a program needs updating, then it'll have to be done via the Rails console.

Teacher Stuff

A Teacher needs to do the following:

Get Classrooms

Request

GET https://education-api.zooniverse.org/teachers/classrooms/?program_id=1

Response (Success)

200 OK

Body:

{
  "data": [
    {
      "id": "1265",
      "type": "classrooms",
      "attributes": {
        "name": "Zoo Class",
        "join-token": "6b051b8be8c8e57c",
        "school": "Zootown",
        "subject": "Zooniverse classroom",
        "description": "A sample classrom",
        "classifications-count": 0
      },
      "relationships": {
        "groups": {
          "data": []
        },
        "students": {
          "data": [
            {
              "id": "4247",
              "type": "student-users"
            },
            {
              "id": "4245",
              "type": "student-users"
            },
            {
              "id": "4246",
              "type": "student-users"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "4247",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1459736",
        "zooniverse-login": "zootester3",
        "zooniverse-display-name": "zootester3",
        "classifications-count": 0
      }
    },
    {
      "id": "4245",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1459668",
        "zooniverse-login": "zootester1",
        "zooniverse-display-name": "zootester1",
        "classifications-count": 0
      }
    },
    {
      "id": "4246",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1459734",
        "zooniverse-login": "zootester2",
        "zooniverse-display-name": "zootester2",
        "classifications-count": 0
      }
    }
  ]
}

Create Classroom

Request

POST https://education-api.zooniverse.org/teachers/classrooms/

Body:

{
  "data": {
    "attributes": {
      "name": "Zoo Class",
      "subject": "Zooniverse classroom",  //Optional
      "school": "Zootown",  //Optional
      "description": "A sample classrom"  //Optional
    },
    relationships: {
      program: {
        data: {
          id: '1',
          type: 'programs'
        }
      }
    }
  }
}

Response (Success)

201 Created

Body:

{
  "data": {
    "id": "1265",
    "type": "classrooms",
    "attributes": {
      "name": "Zoo Class",
      "join-token": "6b051b8be8c8e57c",
      "school":"Zootown",
      "subject":
      "Zooniverse classroom",
      "description": "A sample classrom",
      "classifications-count": 0
    },
    "relationships": {
      "groups": {
        "data": []
      },
      "program": {
        "data": { 
          "id": "1",
          type: "programs"
        }
      },
      "students": {
        "data": []
      }
    }
  }
}

Edit Classroom

Request

PUT https://education-api.zooniverse.org/teachers/classrooms/1265

Body:

{
  "data": {
    "attributes": {
      "name": "Zoo Class???",
      "subject": "Zooniverse classroom...",
      "school": "Zootown!!!",
      "description": "A sample classrom..."
    }
  }
}

Response (Success)

204 No Content

Delete Classroom

Request

DELETE https://education-api.zooniverse.org/teachers/classrooms/1288

Response (Success)

204 No Content

Delete Student from Classrom

Request

DELETE https://education-api.zooniverse.org/teachers/classrooms/1265/student_users/4246

Response (Success)

204 No Content

Get Assignments

Request

https://education-api.zooniverse.org/assignments?classroom_id=365

Body:

{
  "data": [
    {
      "id": "303",
      "type": "assignments",
      "attributes": {
        "name": "Hubble's Law",
        "metadata": {
          "classifications_target": "10"
        },
        "classroom_id": 365,
        "workflow_id": "2218",
        "subject_set_id": null
      },
      "relationships": {
        "student_assignments": {
          "data": [
            {
              "id": "250",
              "type": "student_assignments"
            },
            {
              "id": "252",
              "type": "student_assignments"
            }
          ]
        },
        "student_users": {
          "data": [
            {
              "id": "306",
              "type": "student_users"
            },
            {
              "id": "307",
              "type": "student_users"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": "249",
      "type": "student_assignments",
      "attributes": {
        "student_user_id": 306,
        "classifications_count": 0
      }
    },
    {
      "id": "251",
      "type": "student_assignments",
      "attributes": {
        "student_user_id": 307,
        "classifications_count": 0
      }
    }
  ]
}

Create Assignment

Request

Body:

{
  "data": {
    "attributes": {
      "name": "Galaxy Zoo 101",
      "metadata": {
        "classifications_target": "22"
      },
      "workflow_id": "3037"
    },
    "relationships": {
      "classroom": {
        "data": {
          "id": "376",
          "type": "classrooms"
        }
      }
    }
  }
}

Response

201 Created

{
  "data": {
    "id": "318",
    "type": "assignments",
    "attributes": {
      "name": "Galaxy Zoo 101",
      "metadata": {
        "classifications_target": "22"
      },
      "classroom_id": 376,
      "workflow_id": "3037",
      "subject_set_id": null
    },
    "relationships": {
      "student_assignments": {
        "data": []
      },
      "student_users": {
        "data": []
      }
    }
  }
}

Edit Assignment

TBD

Delete Assignment

TBD

Student Stuff

Join Classroom

Request

POST https://education-api.zooniverse.org/students/classrooms/1265/join

Body:

{
  "join_token": "6b051b8be8c8e57c"
}

Response (Success)

201 Created

Body:

{
  "data": {
    "id": "1265",
    "type": "classrooms",
    "attributes": {
      "name": "Zoo Class",
      "join-token":"6b051b8be8c8e57c",
      "school": "Zootown",
      "subject": "Zooniverse classroom",
      "description": "A sample classrom",
      "classifications-count": 0
    },
    "relationships": {
      "groups": {
        "data": []
      },
      "students": {
        "data": [
          {"id": "4247", "type": "student-users"},
          {"id": "4245", "type": "student-users"},
          {"id": "4248", "type": "student-users"}
        ]
      }
    }
  },
  "included":[
    {
      "id": "4247",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1459736",
        "zooniverse-login": "zootester3",
        "zooniverse-display-name": "zootester3",
        "classifications-count": 0
      }
    },
    {
      "id": "4245",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1459668",
        "zooniverse-login": "zootester1",
        "zooniverse-display-name": "zootester1",
        "classifications-count": 0
      }
    },
    {
      "id": "4248",
      "type": "student-users",
      "attributes": {
        "zooniverse-id": "1475095",
        "zooniverse-login": "zootester4",
        "zooniverse-display-name": "zootester4",
        "classifications-count": 0
      }
    }
  ]
}

Response (Error - Already Joined)

422 Unprocessable Entity

Body:

{
  "errors": [
    {
      "status": 422,
      "source": {
        "pointer": "/data/attributes/id"
      },
      "detail": "cannot join"
    }
  ]
}

Response (Error - Can't Find Classroom / Invalid Join Token(?))

404 Not Found

Body: a 404 page

Get Assignments

TBD

srallen commented 6 years ago

I've updated to include the programs resource, and updated the classroom and assignment examples per the updates to the API.