요청 일괄 처리

이 문서에서는 API 호출을 일괄 처리하여 클라이언트가 수행해야 하는 HTTP 연결 수를 줄이는 방법을 보여줍니다.

이 문서에서는 특히 HTTP 요청을 전송하여 일괄 요청을 수행하는 방법을 설명합니다. 대신 Google 클라이언트 라이브러리를 사용하여 일괄 요청을 하는 경우 클라이언트 라이브러리의 문서를 참고하세요.

개요

클라이언트가 수행하는 각 HTTP 연결에는 어느 정도의 오버헤드가 수반됩니다. Google Classroom API는 일괄 처리를 지원하므로 클라이언트에서 단일 HTTP 요청에 여러 개의 API 호출을 넣을 수 있습니다.

다음과 같은 경우에 일괄 처리를 사용할 수 있습니다.

  • 많은 과정의 출석부 검색
  • 강의를 일괄적으로 만들거나 업데이트합니다.
  • 다수의 코스 출석부 추가
  • 많은 수의 사용자가 참여할 수 있는 강의 목록을 검색합니다.

두 경우 모두 각 호출을 개별적으로 보내는 대신 단일 HTTP 요청으로 그룹화할 수 있습니다. 모든 내부 요청은 동일한 Google API로 이동해야 합니다.

일괄 요청 하나에 포함할 수 있는 호출 수는 50개로 제한됩니다. 이보다 더 많이 호출해야 하는 경우 여러 일괄 요청을 사용합니다.

참고: Google Classroom API용 일괄 처리 시스템은 OData 일괄 처리 시스템과 동일한 구문을 사용하지만 시맨틱스는 다릅니다.

일괄 처리 세부정보

일괄 요청은 하나의 HTTP 요청으로 결합된 여러 API 호출로 구성되며, 이 요청을 API 검색 문서에 지정된 batchPath로 보낼 수 있습니다. 기본 경로는 /batch/api_name/api_version입니다. 이 섹션에서는 일괄 처리 구문을 세부적으로 설명하며 뒷부분에서 예시를 제시합니다.

참고: 일괄 처리된 n 요청 집합은 사용량 한도 계산 시 하나의 요청이 아닌 n 요청으로 계산됩니다. 일괄 요청은 처리하기 전에 일련의 요청으로 분리됩니다.

일괄 요청의 형식

일괄 요청은 여러 개의 Google Classroom API 호출이 포함된 단일 표준 HTTP 요청이며 multipart/mixed 콘텐츠 유형을 사용합니다. 이 기본 HTTP 요청 내의 각 부분에는 중첩된 HTTP 요청이 포함되어 있습니다.

각 부분은 자체 Content-Type: application/http HTTP 헤더로 시작됩니다. 선택사항인 Content-ID 헤더가 있는 경우도 있습니다. 그러나 부분 헤더는 부분의 시작을 표시하기 위해 있을 뿐이며 중첩된 요청과는 별개입니다. 서버에서 일괄 요청을 개별 요청으로 해체하면 부분 헤더는 무시됩니다.

각 부분의 본문은 자체 동사와 URL, 헤더, 본문을 포함하며 그 자체로 완전한 HTTP 요청입니다. HTTP 요청은 URL의 경로 부분만 포함해야 합니다. 전체 URL은 일괄 요청에서 허용되지 않기 때문입니다.

외부 일괄 요청의 HTTP 헤더(Content-Type과 같은 Content- 헤더 제외)는 일괄 처리되는 각 요청에 모두 적용됩니다. 특정 HTTP 헤더를 외부 요청과 개별 호출에 모두 지정하는 경우 개별 호출 헤더의 값이 외부 일괄 요청 헤더의 값을 재정의합니다. 개별 호출의 헤더는 해당 호출에만 적용됩니다.

예를 들어 특정 호출에 승인 헤더를 제공하는 경우 이 헤더는 해당 호출에만 적용됩니다. 외부 요청에 승인 헤더를 제공하는 경우 이 헤더는 개별 호출에서 자체 승인 헤더로 재정의하지 않는 이상 모든 개별 호출에 적용됩니다.

서버는 일괄 요청을 수신하면 외부 요청의 쿼리 매개변수와 헤더를 각 부분에 적절히 적용한 다음 각 부분을 개별 HTTP 요청처럼 취급합니다.

일괄 요청 응답

서버 응답은 multipart/mixed 콘텐츠 유형의 단일 표준 HTTP 응답입니다. 각 부분은 일괄 요청에 포함된 요청 중 하나에 대한 응답이며 요청 순서와 동일한 순서로 표시됩니다.

요청의 부분과 마찬가지로 각 응답 부분에는 상태 코드, 헤더, 본문을 포함한 완전한 HTTP 응답이 포함됩니다. 또한 요청의 부분과 마찬가지로 각 응답 부분 앞에는 Content-Type 헤더가 붙어 부분의 시작을 표시합니다.

요청의 특정 부분에 Content-ID 헤더가 있는 경우 해당하는 응답 부분에도 일치하는 Content-ID 헤더가 표시되며 원래 값 앞에는 문자열 response-가 붙습니다(다음 예시 참조).

참고: 서버는 호출을 임의의 순서로 수행할 수 있습니다. 지정한 순서에 따라 실행된다고 생각하면 안 됩니다. 2개의 호출이 지정된 순서에 따라 실행되도록 하려면 1개의 요청으로 두 호출을 보내면 안 됩니다. 첫 번째 호출을 단독으로 보낸 다음 첫 번째 호출의 응답을 기다렸다가 두 번째 호출을 보내야 합니다.

다음 예는 Google Classroom API에서 일괄 처리를 사용하는 방법을 보여줍니다.

일괄 요청 예

POST https://classroom.googleapis.com/batch HTTP/1.1
Authorization: Bearer your_auth_token
Content-Type: multipart/mixed; boundary=batch_foobarbaz
Content-Length: total_content_length

--batch_foobarbaz
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: <item1:12930812@classroom.example.com>

PATCH /v1/courses/134529639?updateMask=name HTTP/1.1
Content-Type: application/json; charset=UTF-8
Authorization: Bearer your_auth_token

{
  "name": "Course 1"
}
--batch_foobarbaz
Content-Type: application/http
Content-Transfer-Encoding: binary
MIME-Version: 1.0
Content-ID: <item2:12930812@classroom.example.com>

PATCH /v1/courses/134529901?updateMask=section HTTP/1.1
Content-Type: application/json; charset=UTF-8
Authorization: Bearer your_auth_token
{
  "section": "Section 2"
}
--batch_foobarbaz--

일괄 응답 예시

이전 섹션의 요청 예에 대한 응답입니다.

HTTP/1.1 200
Content-Length: response_total_content_length
Content-Type: multipart/mixed; boundary=batch_foobarbaz

--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item1:12930812@classroom.example.com>

HTTP/1.1 200 OK
Content-Type application/json
Content-Length: response_part_1_content_length

{
  "id": "134529639",
  "name": "Course 1",
  "section": "Section 1",
  "ownerId": "116269102540619633451",
  "creationTime": "2015-06-25T14:23:56.535Z",
  "updateTime": "2015-06-25T14:33:06.583Z",
  "enrollmentCode": "6paeflo",
  "courseState": "PROVISIONED",
  "alternateLink": "http://classroom.google.com/c/MTM0NTI5NjM5"
}
--batch_foobarbaz
Content-Type: application/http
Content-ID: <response-item2:12930812@classroom.example.com>

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: response_part_2_content_length

{
  "id": "134529901",
  "name": "Course 1",
  "section": "Section 2",
  "ownerId": "116269102540619633451",
  "creationTime": "2015-06-25T14:23:08.761Z",
  "updateTime": "2015-06-25T14:33:06.490Z",
  "enrollmentCode": "so75ha5",
  "courseState": "PROVISIONED",
  "alternateLink": "http://classroom.google.com/c/MTM0NTI5OTAx"
}
--batch_foobarbaz--

클라이언트 라이브러리 사용

다음 코드 샘플은 Google API 클라이언트 라이브러리를 사용하여 일괄 요청을 하는 방법을 보여줍니다. 라이브러리 설치 및 설정 방법에 관한 자세한 내용은 해당 빠른 시작 가이드를 참조하세요.

.NET

classroom/snippets/ClassroomSnippets/BatchAddStudents.cs
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Classroom.v1;
using Google.Apis.Classroom.v1.Data;
using Google.Apis.Requests;
using Google.Apis.Services;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ClassroomSnippets
{
    // Class to demonstrate the use of Classroom Batch Add Students API
    public class BatchAddStudents
    {
        /// <summary>
        /// Add multiple students in a specified course.
        /// </summary>
        /// <param name="courseId">Id of the course to add students.</param>
        /// <param name="studentEmails">Email address of the students.</param>
        public static void ClassroomBatchAddStudents(string courseId,
            List<string> studentEmails)
        {
            try
            {
                /* Load pre-authorized user credentials from the environment.
                 TODO(developer) - See https://developers.google.com/identity for 
                 guides on implementing OAuth2 for your application. */
                GoogleCredential credential = GoogleCredential.GetApplicationDefault()
                    .CreateScoped(ClassroomService.Scope.ClassroomRosters);

                // Create Classroom API service.
                var service = new ClassroomService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Classroom Snippets"
                });

                var batch = new BatchRequest(service, "https://classroom.googleapis.com/batch");
                BatchRequest.OnResponse<Student> callback = (student, error, i, message) =>
                {
                    if (error != null)
                    {
                        Console.WriteLine("Error adding student to the course: {0}", error.Message);
                    }
                    else
                    {
                        Console.WriteLine("User '{0}' was added as a student to the course.",
                            student.Profile.Name.FullName);
                    }
                };
                foreach (var studentEmail in studentEmails)
                {
                    var student = new Student() {UserId = studentEmail};
                    var request = service.Courses.Students.Create(student, courseId);
                    batch.Queue<Student>(request, callback);
                }

                Task.WaitAll(batch.ExecuteAsync());
            }
            catch (Exception e)
            {
                // TODO(developer) - handle error appropriately
                if (e is AggregateException)
                {
                    Console.WriteLine("Credential Not found");
                }
                else if (e is GoogleApiException)
                {
                    Console.WriteLine("Course does not exist.");
                }
                else
                {
                    throw;
                }
            }
        }
    }
}

Java

classroom/snippets/src/main/java/BatchAddStudents.java
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.classroom.Classroom;
import com.google.api.services.classroom.ClassroomScopes;
import com.google.api.services.classroom.model.Student;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate the use of Classroom Batch Add Students API */
public class BatchAddStudents {

  /* Scopes required by this API call. If modifying these scopes, delete your previously saved
  tokens/ folder. */
  static ArrayList<String> SCOPES =
      new ArrayList<>(Arrays.asList(ClassroomScopes.CLASSROOM_ROSTERS));

  /**
   * Add multiple students in a specified course.
   *
   * @param courseId - Id of the course to add students.
   * @param studentEmails - Email address of the students.
   * @throws IOException - if credentials file not found.
   * @throws GeneralSecurityException - if a new instance of NetHttpTransport was not created.
   */
  public static void batchAddStudents(String courseId, List<String> studentEmails)
      throws GeneralSecurityException, IOException {

    // Create the classroom API client.
    final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
    Classroom service =
        new Classroom.Builder(
                HTTP_TRANSPORT,
                GsonFactory.getDefaultInstance(),
                ClassroomCredentials.getCredentials(HTTP_TRANSPORT, SCOPES))
            .setApplicationName("Classroom samples")
            .build();

    BatchRequest batch = service.batch();
    JsonBatchCallback<Student> callback =
        new JsonBatchCallback<>() {
          public void onSuccess(Student student, HttpHeaders responseHeaders) {
            System.out.printf(
                "User '%s' was added as a student to the course.\n",
                student.getProfile().getName().getFullName());
          }

          public void onFailure(GoogleJsonError error, HttpHeaders responseHeaders) {
            System.out.printf("Error adding student to the course: %s\n", error.getMessage());
          }
        };
    for (String studentEmail : studentEmails) {
      Student student = new Student().setUserId(studentEmail);
      service.courses().students().create(courseId, student).queue(batch, callback);
    }
    batch.execute();
  }
}

2,399필리핀

classroom/snippets/src/ClassroomBatchAddStudents.php
use Google\Client;
use Google\Service\Classroom;
use Google\Service\Classroom\Student;
use Google\Service\Exception;

function batchAddStudents($courseId, $studentEmails)
{
    /* Load pre-authorized user credentials from the environment.
    TODO(developer) - See https://developers.google.com/identity for
     guides on implementing OAuth2 for your application. */
    $client = new Client();
    $client->useApplicationDefaultCredentials();
    $client->addScope("https://www.googleapis.com/auth/classroom.profile.emails");
    $service = new Classroom($client);
    $service->getClient()->setUseBatch(true);
    //create batch
    $batch = $service->createBatch();
    foreach ($studentEmails as $studentEmail) {
        $student = new Student([
            'userId' => $studentEmail
        ]);
        $request = $service->courses_students->create($courseId, $student);
        $requestId = $studentEmail;
        $batch->add($request, $requestId);
    }
    //executing request
    $results = $batch->execute();
    foreach ($results as $responseId => $student) {
        $studentEmail = substr($responseId, strlen('response-') + 1);
        if ($student instanceof Exception) {
            $e = $student;
            printf("Error adding user '%s' to the course: %s\n", $studentEmail,
                $e->getMessage());
        } else {
            printf("User '%s' was added as a student to the course.\n",
                $student->profile->name->fullName, $courseId);
        }
    }
    $service->getClient()->setUseBatch(false);
    return $results;
}

Python

course_id = '123456'
student_emails = ['alice@example.edu', 'bob@example.edu']
def callback(request_id, response, exception):
    if exception is not None:
        print 'Error adding user "{0}" to the course course: {1}'.format(
            request_id, exception)
    else:
        print 'User "{0}" added as a student to the course.'.format(
            response.get('profile').get('name').get('fullName'))
batch = service.new_batch_http_request(callback=callback)
for student_email in student_emails:
    student = {
        'userId': student_email
    }
    request = service.courses().students().create(courseId=course_id,
                                                  body=student)
    batch.add(request, request_id=student_email)
batch.execute(http=http)