I want to run my FastAPI for multiprocessing but when I try to run using uvicorn with reload and workers but it could not find my login endpoint.
It says "detail": "Not Found" when I hit the endpoint this is my object_counter_api.py
app = FastAPI(
title="Object Counter API",
description="REST API for Object Counter Service.",
version="0.1",
contact={ "name": "my_endpoint",
"url": "https://my_endpoint.com",
"email": "sales#my_endpoint.com"
}
)
# Allow cors error mitigation
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"]
)
class ObjectCounterAPI:
def run_object_counter(self, host, port):
ABLogger.info(self, "running object counter API!")
self.setup()
uvicorn.run("object_counter_api:app", host=self.vehicle_config.host,port=self.vehicle_config.port, reload=True, workers=2)
def setup(self):
#app.post("/vehicle/api/v1/login")
async def login(request: LoginRequest):
ABLogger.info(self, "login credentials check!")
access_token = await self.authenticate_user(request.username, request.password)
response = LoginResponse(access_token=access_token, token_type="bearer")
return response
this is my main.py
if __name__ == "__main__":
#hydra.main(config_path=root / "hydra_config", config_name="debug", version_base=None)
def main(hydra_config: DictConfig):
api = ObjectCounterAPI(hydra_config)
mp.Process(target = api.run_object_counter(host=hydra_config.api.vehicle_counter.host, port=hydra_config.api.vehicle_counter.port)).start()
main()
Related
I've set up DRF-YASG documentation for my Django project, but the endpoints that require authentication show no parameters (fields to fill) even when logged as an authorized user.
swagger ui
In fact, none of my endpoints show their respective parameter fields in the UI.
Here are my REST_FRAMEWORK settings in settings.py :
REST_FRAMEWORK = {
"NON_FIELD_ERRORS_KEY": "errors",
"DEFAULT_AUTHENTICATION_CLASSES":(
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication"
),
"DEFAULT_PERMISSON_CLASSES":(
"rest_framework.permissions.IsAuthenticated"
)
}
and urls.py:
from django.contrib import admin
from django.urls import path, include, re_path
from EmployeeApp import views
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact#snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
name='schema-json'),
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('admin/', admin.site.urls),
path('', views.api_home),
path('api/', include('EmployeeApp.urls')),
path('api/auth/', include('accounts.urls')),
]
I am using standard token authentication and here are my views.
from django.contrib.auth import authenticate
from .serializers import SignUpSerializer, UserSerializer
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
class SignUpView(generics.GenericAPIView):
serializer_class = SignUpSerializer
def post(self, request: Request):
data = request.data
serializer = self.serializer_class(data=data)
if serializer.is_valid():
serializer.save()
response = {
"message": "User Created Successfully",
"data": serializer.data
}
return Response(data=response, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
#swagger_auto_schema(request_body=UserSerializer)
def post(self, request: Request):
email = request.data.get('email')
password = request.data.get('password')
user = authenticate(email=email, password=password)
if user:
response = {
"message": "Login Successful",
"token": user.auth_token.key
}
return Response(data=response, status=status.HTTP_200_OK)
else:
return Response(data={"message": "Invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED)
def get(self, request: Request):
content = {
"user": str(request.user),
"auth": str(request.auth)
}
return Response(data=content, status=status.HTTP_200_OK)
In Postman everything works as expected, but in the Swagger documentation the authenticated user is not being recognized and the parameter fields on endpoints are missing.
Not sure if these two issues are connected, but I would apprechiate any type of helpful input on this!
I have tested the endpoints with direct Postman requests and everything works as expected.
Here is the endpoint to Create(POST) a company as a logged User:
class CompanyCreate(APIView):
permission_classes = [IsAuthenticated]
#swagger_auto_schema(
operation_summary="Create a company",
operation_description="This allows logged-in user to create a company"
)
def post(self, request):
company_name_exists = Companies.objects.filter(company_name=request.data['company_name']).exists()
if company_name_exists:
raise ValidationError("Company with the same name already exists")
data = {**request.data, 'user_id': request.auth.user_id}
serializer = CompanySerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and it's serializer:
class CompanySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = Companies
fields = ('user_id', 'company_name', 'company_description', 'company_logo')
def create(self, validated_data):
company, is_created = Companies.objects.get_or_create(
company_name=validated_data['company_name'],
company_description=validated_data['company_description'],
company_logo=validated_data['company_logo'],
user_id=validated_data['user_id'],
)
return company
I've attached `
#swagger_auto_schema(request_body=UserSerializer)
`
to my login endpoint and it gives me a filed to put the request body data in a JSON format.
enter image description here
that works, but it still does not show the Swagger UI parameter fields and the auth does not persist when I try to test endpoints that require it.
I am trying to create a REST API with 2 methods GET and POST. Here is the work I have done:
Using Terraform to deploy AWS services.
Created 2 REST API methods - GET and POST.
Integrated API Gateway to AWS lambda. I created two lambdas, one for each method. The objective is to get "Hello World" as a response. The two lambdas (handlers) are identical in code.
The problem: After the deployment, it worked as expected (200) when I tried to hit POST. However, GET is giving a 500 error. This is what I see on the AWS console.
[When I am using type='MOCK' for GET]Execution failed due to configuration error: No match for output mapping and no default output mapping configured. Endpoint Response Status Code: 200
[When I am using type = 'AWS_PROXY' for GET] Lambda invocation failed with status: 403. Lambda request id: 5b23639d-f6fb-4130-acf0-15db9a2f76b0
Method completed with status: 500
Why is it that POST is working and GET is throwing an error? Any leads to rectifying this error or providing some explanation are appreciated.
Below is my Terraform configuration.
Note: I included only the "aws_api_gateway_*" resources. IAM roles, Lambdas, Lambda permissions are all good.
# Lambda handler - This is the same for both GET and POST. I used the same in both lambdas integrated to GET and POST.
import json
def lambda_handler(event, context):
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json"
},
"body": json.dumps("Hello World")
}
################################################################################
# REST API and Resource
################################################################################
resource "aws_api_gateway_rest_api" "hello_world_v1" {
name = "hello_world_v1"
}
resource "aws_api_gateway_resource" "hello_world_v1" {
parent_id = aws_api_gateway_rest_api.hello_world_v1.root_resource_id
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
path_part = "test"
}
################################################################################
# GET - method and integration
################################################################################
resource "aws_api_gateway_method" "hello_world_v1_get" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
resource_id = aws_api_gateway_resource.hello_world_v1.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "hello_world_v1_get" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
resource_id = aws_api_gateway_method.hello_world_v1_get.resource_id
http_method = aws_api_gateway_method.hello_world_v1_get.http_method
integration_http_method = "GET"
type = "AWS_PROXY"
uri = aws_lambda_function.lambda_hello_world_v1_get.invoke_arn
# I initially didn't use this request template.
# I tried this after reading it somewhere while I was attempting to search for a solution.
# However,using or not using, didn't work out.
request_templates = {
"application/json" = jsonencode(
{
statusCode = 200
}
)
}
}
################################################################################
# POST - method and integration
################################################################################
resource "aws_api_gateway_method" "hello_world_v1_post" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
resource_id = aws_api_gateway_resource.hello_world_v1.id
http_method = "POST"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "hello_world_v1_post" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
resource_id = aws_api_gateway_method.hello_world_v1_post.resource_id
http_method = aws_api_gateway_method.hello_world_v1_post.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.lambda_hello_world_v1_post.invoke_arn
}
################################################################################
# Stage and Deployment
################################################################################
resource "aws_api_gateway_deployment" "hello_world_v1" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
depends_on = [
aws_api_gateway_method.hello_world_v1_get,
aws_api_gateway_method.hello_world_v1_post
]
}
resource "aws_api_gateway_stage" "hello_world_v1" {
deployment_id = aws_api_gateway_deployment.hello_world_v1.id
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
stage_name = "development"
}
According to the documentation:
integration_http_method - (Optional) The integration HTTP method (GET,
POST, PUT, DELETE, HEAD, OPTIONs, ANY, PATCH) specifying how API
Gateway will interact with the back end. Required if type is AWS,
AWS_PROXY, HTTP or HTTP_PROXY. Not all methods are compatible with all
AWS integrations. e.g., Lambda function can only be invoked via POST.
In a very simple way, the http_method attribute refers to the HTTP Method of your endpoint, the integration_http_method is the HTTP method of the call that API Gateway will do to invoke the Lambda function.
Just change it to POST:
resource "aws_api_gateway_integration" "hello_world_v1_get" {
rest_api_id = aws_api_gateway_rest_api.hello_world_v1.id
resource_id = aws_api_gateway_method.hello_world_v1_get.resource_id
http_method = aws_api_gateway_method.hello_world_v1_get.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.lambda_hello_world_v1_get.invoke_arn
# I initially didn't use this request template.
# I tried this after reading it somewhere while I was attempting to search for a solution.
# However,using or not using, didn't work out.
request_templates = {
"application/json" = jsonencode(
{
statusCode = 200
}
)
}
}
I am making an API with Flask-RESTFUL, but when I make the POST
http://127.0.0.1:5000/bot?id_articulo=1&url_articulo=www.wiki.org
I get the message
"message": "The browser (or proxy) sent a request that this server could not understand."
My python code is
from flask import Flask
from flask_restful import Resource, Api, reqparse
import pandas as pd
app = Flask(__name__)
api = Api(app)
class Bot(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('id_articulo' , required=True, type=int)
parser.add_argument('url_articulo', required=True, type=str)
args = parser.parse_args()
print(args)
data_articulo = pd.read_csv('articulos.csv')
print(data_articulo)
if args['url_articulo'] in list(data_articulo['url']):
return {
'mensage': f"El artÃculo '{args['url_articulo']}' ya existe."
}, 409
else:
nueva_columna = pd.DataFrame({
'id_articulo': [args['id_articulo']],
'url': [args['url_articulo']],
})
data_articulo = data_articulo.append(nueva_columna, ignore_index=True)
data_articulo.to_csv('articulos.csv', index=False)
return {'data': data_articulo.to_dict()}, 200
api.add_resource(Bot, '/bot', methods=['POST'])
if __name__ == '__main__':
app.run()
Now, I noticed that the error message is thrown only when I am in a virtual environment whose requirements.txt is
aniso8601==9.0.1
click==8.1.3
colorama==0.4.5
Flask==2.1.2
Flask-RESTful==0.3.9
importlib-metadata==4.12.0
itsdangerous==2.1.2
Jinja2==3.1.2
joblib==1.1.0
MarkupSafe==2.1.1
numpy==1.23.1
pandas==1.4.3
python-dateutil==2.8.2
pytz==2022.1
six==1.16.0
Werkzeug==2.1.2
zipp==3.8.0
By this far, I don't have a clue about what is going on and it makes me think that the flask_restful library have issues with virtual environments and I would like to know how to make this work properly in one.
First time using Locust. I have a Flask App that requires user to login to access most routes.
I cant get Locust to successfully login to my Flask App.
Here is my Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED", "password": "REDACTED"},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
#task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
Here is the login function of my Flask App: (with a few debug statements added)
#users.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST': ##DEBUG
logging.debug(f"debug0: inside login func with method == POST") ##DEBUG
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
if form.validate_on_submit():
logging.debug(f"debug0.1: inside validate_on_submit") ##DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") ##DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") ##DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") ##DEBUG
return render_template('login.html', title='Login', form=form)
When i run Locust, I get this output:
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting web monitor at *:8089
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting Locust 0.11.0
[2019-09-16 18:03:14,069] Mac-mini-3.local/INFO/locust.runners: Hatching and swarming 2 clients at the rate 1 clients/s...
[2019-09-16 18:03:14,138] Mac-mini-3.local/ERROR/stderr: /Users/myuser/.local/share/virtualenvs/locustio-gB1-mbqd/lib/python3.7/site-packages/urllib3/connectionpool.py:851: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning)
[2019-09-16 18:03:14,162] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:14,183] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
[2019-09-16 18:03:14,213] Mac-mini-3.local/INFO/stdout: DEBUG list: response.status_code = 200
[2019-09-16 18:03:15,112] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:15,137] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
I'm not concerned about the 'InsecureRequestWarning' as this is because I am using a self signed cert and i have disabled verification with 'self.client.verify = False'
The csrftoken looks correct.
From the Flask App itself, I get this output:
DEBUG:user:debug0: inside login func with method == POST
INFO:flask_wtf.csrf:The CSRF token is missing.
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
So, it's hitting the login function (proven by debug0) but it's not getting into the 'form.validate_on_submit()' conditional.
So far I have spent all day on this, reading articles and trying a lot of things, ie adding the X-CSRFToken headers.
I feel I am missing something fundamental, and would really appreciate some help.
thanks,
WJ
Ok, I solved it, so thought I would share the anwser for anyone else that comes across this. As suggested by #user10788336 its is not a Locust issue.
The issue was that when POSTing to the flask route, the form was not being validated (ie form.validate() was not getting set).
So, I made two changes.
1) changed the POST to have an additional form item which i called "test-mode" and I set the value to "locust-test"
here is the new Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED",
"password": "REDACTED",
"test-mode": "locust-test"
},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
#task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
The diff between old and new is:
< {"email": "REDACTED", "password": "REDACTED"},
---
> {"email": "REDACTED",
> "password": "REDACTED",
> "test-mode": "locust-test"
> },
2) I changed my login function the Flask app:
The change is that I don't need the form to be validated, so I skip that ONLY when I detect that I am running in test-mode.
here is the new login function:
#users.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
# shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
form_is_ok = False
if request.method == 'POST':
if request.form.get('test-mode') == 'locust-test':
form_is_ok = True
else:
form_is_ok = form.validate_on_submit()
if form_is_ok:
logging.debug(f"debug0.1: inside validate_on_submit") # DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") # DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") # DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") # DEBUG
return render_template('login.html', title='Login', form=form)
The diff between old and new is:
< if form.validate_on_submit():
---
>
> # shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
> form_is_ok = False
> if request.method == 'POST':
> if request.form.get('test-mode') == 'locust-test':
> form_is_ok = True
> else:
> form_is_ok = form.validate_on_submit()
>
> if form_is_ok:
I think this is still secure ... thoughts on that?
I might add a config variable, that disables/enables this functionality.
And it works!!!!
BTW, Locust is awesome!
Hope this helps.
cheers,
WJ
Can you share the code for what the form.validate_on_submit method is expecting/validating? Chances are there is a hidden field in the login form that is acting as a dynamic token and/or you're missing a required field. Can you also share the HTML source of the login form?
I'd also be curious to see you add an additional debug statement in your login method that outputs the value of the CSRF token, to make sure it is valid, e.g.
def login(self):
print(f"DEBUG: login csrftoken = {self.csrftoken}")
response = self.client.post("/login",
{"email": "REDACTED",
"password": "REDACTED",
"test-mode": "locust-test"
},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
I'd also be curious to see if there are any error messages when you submit the form without a valid CSRF token. Does it return a 200 status code and report the invalid token?
My guess is that it's something to do with the CSRF token not being valid or handled correctly.
Is this an older or customized version of Flask login? I'm not seeing an X-CSRFToken header method in the latest version of Flask login docs at https://flask-login.readthedocs.io/en/latest/
I'm getting an HTTP 500 error when trying to run the sample code (python) for inserting an activity on behalf of a user. I've set up domain wide delegation and have included all the correct scopes. I've successfully run with domain delegation for creating circles, adding people to circles, reading posts, comments and profiles but for some reason I cannot get the code to work for inserting a post on behalf of a user. Any ideas?
Code and error follow (private info redacted):
import httplib2
import pprint
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
SERVICE_ACCOUNT_EMAIL = 'svc-acct#developer.gserviceaccount.com'
SERVICE_ACCOUNT_PKCS12_FILE_PATH = '/path/privatekey.pem'
USER_EMAIL = 'email#domain.com'
SCOPES = ['https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/plus.stream.read',
'https://www.googleapis.com/auth/plus.stream.write',
'https://www.googleapis.com/auth/plus.circles.read',
'https://www.googleapis.com/auth/plus.circles.write',
'https://www.googleapis.com/auth/plus.profiles.read']
def authenticate():
print 'Authenticate the domain for %s' % USER_EMAIL
f = open(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'rb')
key = f.read()
f.close()
credentials = SignedJwtAssertionCredentials(SERVICE_ACCOUNT_EMAIL, key,
scope=SCOPES, sub=USER_EMAIL)
http = httplib2.Http()
http = credentials.authorize(http)
return build('plusDomains', 'v1', http=http)
def activitiesInsert(service):
user_id = 'me'
print 'Inserting activity'
result = service.activities().insert(
userId = user_id,
body = {
'object' : {
'originalContent' : 'Happy Monday! #caseofthemondays'
},
'access' : {
'items' : [{
'type' : 'domain'
}],
# Required, this does the domain restriction
'domainRestricted': True
}
}).execute()
print 'result = %s' % pprint.pformat(result)
if __name__ == '__main__':
service = authenticate()
activitiesInsert(service)
python addpost.py
Authenticate the domain for email#domain.com
Inserting activity
Traceback (most recent call last):
File "addpost.py", line 72, in
activitiesInsert(service)
File "addpost.py", line 64, in activitiesInsert
'domainRestricted': True
File "build/bdist.macosx-10.6-intel/egg/oauth2client/util.py", line 132, in
positional_wrapper
File "build/bdist.macosx-10.6-intel/egg/apiclient/http.py",
line 723, in execute
apiclient.errors.httperror
HttpError 500 when requesting https://www.googleapis.com/plusDomains/v1/people/me/activities?alt=json returned ""