Mengakses App Engine dengan Remote API

Google Cloud CLI menyertakan paket remote_api yang memungkinkan Anda mengakses layanan App Engine secara transparan dari aplikasi Go apa pun. Misalnya, Anda dapat menggunakan Remote API untuk mengakses Datastore dari aplikasi yang dijalankan oleh komputer lokal atau salah satu aplikasi App Engine Anda lainnya.

Untuk melihat isi paket remote_api, lihat referensi dari paket remote_api.

Penggunaan Remote API

Pertama, tambahkan pengendali dari remote_api url ke app.yaml Anda. Contoh:

- url: /_ah/remote_api
  script: _go_app

Langkah ini akan memetakan URL /_ah/remote_api ke aplikasi Go Anda. Akses ke URL ini dibatasi bagi administrator aplikasi oleh pengendali Remote API.

Kemudian, Anda mengimpor paket remote_api di salah satu paket proyek dengan menambahkan baris berikut ke salah satu file sumber .go Anda:

import _ "google.golang.org/appengine/remote_api"

Selama inisialisasi program, paket remote_api mengidentifikasi pengendali untuk jalur /_ah/remote_api. Garis bawah dalam deklarasi impor berarti "impor paket ini, tetapi kita tidak akan langsung menggunakannya." Tanpa garis bawah, Anda akan menerima pesan penanda error "diimpor tetapi tidak digunakan" pada kompilasi.

Terakhir, Anda mengaplikasikan update ke App Engine. Contoh:

gcloud app deploy app.yaml

Menggunakan Remote API pada Klien Lokal

Remote API dapat digunakan untuk merancang aplikasi lokal yang menggunakan layanan App Engine dan mengakses datastore. Penting untuk diperhatikan bahwa penggunaan Remote API akan menyebabkan penggunaan kuota pada aplikasi yang Anda akses.

Sebelum memulai, pastikan Remote API aktif di aplikasi App Engine Anda. Aplikasi lokal dapat menggunakan Remote API dengan membuat konteks berbasis remote_api.NewRemoteContext, dan menggunakannya sebagai pengganti konteks App Engine reguler di semua panggilan API.

// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/remote_api"
)

func main() {
	const host = "<your-app-id>.appspot.com"

	ctx := context.Background()

	hc, err := google.DefaultClient(ctx,
		"https://www.googleapis.com/auth/appengine.apis",
		"https://www.googleapis.com/auth/userinfo.email",
		"https://www.googleapis.com/auth/cloud-platform",
	)
	if err != nil {
		log.Fatal(err)
	}

	remoteCtx, err := remote_api.NewRemoteContext(host, hc)
	if err != nil {
		log.Fatal(err)
	}

	q := datastore.NewQuery("Greeting").
		Filter("Date >=", time.Now().AddDate(0, 0, -7))

	log.Println(q.Count(remoteCtx))
}

Untuk mengaktifkan kode ini, Anda harus mengambil paket berikut:

$ go get google.golang.org/appengine/...
$ go get golang.org/x/oauth2/...

Anda harus memberikan nama host server yang Anda gunakan dan http.Client dalam panggilan ke NewRemoteContext. http.Client yang disediakan berfungsi untuk meneruskan informasi autentikasi yang diperlukan dalam setiap permintaan.

Pada contoh di atas, DefaultClient dari paket golang.org/x/oauth2/google menghasilkan kredensial OAuth 2 melalui Kredensial Default Aplikasi.

Keterbatasan dan praktik terbaik

Modul remote_api secara optimal dirancang untuk sedapat mungkin, berperilaku sama persis dengan datastore App Engine native. Dalam beberapa kasus, ini berarti melakukan hal-hal yang kurang efisien dibandingkan yang seharusnya. Saat menggunakan remote_api, berikut beberapa hal yang perlu diingat:

Setiap permintaan datastore memerlukan proses dua arah

Karena Anda mengakses datastore melalui HTTP, terdapat sedikit lebih banyak overhead dan latensi dibandingkan ketika Anda mengaksesnya secara lokal. Untuk mempercepat dan mengurangi beban, coba batasi jumlah perjalanan dua arah yang Anda lakukan dengan mengelompokkan get dan put, serta mengambil batch entity dari kueri. Ini merupakan saran yang bagus tidak hanya untuk remote_api, tetapi juga untuk menggunakan datastore secara umum, karena operasi batch hanya dianggap sebagai operasi Datastore tunggal.

Permintaan ke remote_api menggunakan kuota

Karena remote_api beroperasi melalui HTTP, setiap panggilan datastore yang Anda lakukan akan menyebabkan penggunaan kuota untuk permintaan HTTP, byte masuk dan keluar, serta kuota datastore biasa. Ingatlah hal ini jika Anda menggunakan remote_api untuk melakukan update massal.

Batas API sebesar 1 MB berlaku

Seperti saat berjalan secara native, batas 1 MB untuk permintaan dan respons API masih berlaku. Jika entity Anda sangat besar, Anda mungkin perlu membatasi jumlah yang Anda ambil atau tempatkan pada satu waktu agar tetap di bawah batas ini. Sayangnya, hal ini bertentangan dengan meminimalkan perjalanan dua arah. Oleh karena itu, saran terbaiknya adalah menggunakan batch terbesar yang Anda bisa tanpa melampaui batasan ukuran permintaan atau respons. Namun, bagi sebagian besar entity, hal ini mungkin tidak menjadi masalah.

Hindari melakukan iterasi pada kueri

Saat Anda melakukan iterasi pada kueri, SDK akan mengambil entity dari datastore dalam batch berisi 20, dengan mengambil batch baru setiap kali SDK menggunakan batch yang sudah ada. Karena setiap batch harus diambil dalam permintaan terpisah oleh remote_api, metode ini tidak dapat dlakukan secara efisien. Sebagai gantinya, remote_api mengeksekusi kueri yang benar-benar baru untuk setiap batch, menggunakan fungsi offset untuk mendapatkan hasil lebih lanjut.

Jika mengetahui jumlah entity yang diperlukan, Anda dapat melakukan seluruh pengambilan dalam satu permintaan dengan meminta jumlah yang diperlukan.

Jika tidak mengetahui jumlah entity yang diinginkan, Anda dapat menggunakan cursors untuk melakukan iterasi secara efisien pada kumpulan hasil yang besar. Hal ini juga memungkinkan Anda menghindari batas 1000 entity yang diberlakukan pada kueri datastore normal.

Transaksi kurang efisien

Untuk mengimplementasikan transaksi melalui remote_api, metode ini mengumpulkan informasi tentang entity yang diambil di dalam transaksi, bersama dengan salinan entity yang ditempatkan atau dihapus di dalam transaksi. Ketika transaksi melalui proses commitment, semua informasi ini akan dikirimkan ke server App Engine, di mana transaksi harus mengambil kembali semua entity yang digunakan dalam transaksi, memverifikasi bahwa entity tersebut belum dimodifikasi, kemudian menempatkan dan menghapus semua perubahan transaksi dan melakukan commitment pada transaksi. Jika terjadi konflik, server akan melakukan roll back transaksi dan memberi tahu klien, kemudian harus mengulangi prosesnya dari awal.

Pendekatan ini berfungsi dengan baik, dan menduplikasi fungsi yang dihasilkan oleh transaksi di datastore lokal, tetapi tidak efisien. Artinya, gunakan transaksi jika diperlukan, tetapi coba batasi jumlah dan kompleksitas transaksi yang Anda jalankan demi efisiensi.