Nir Alfasi
Nir Alfasi

Reputation: 53525

Getting 'Missing required field: member' when trying to add a member to a google group via API

Trying to use Google admin directory API in order to read members of a google group (organization) - it works fine. When I try to add a member I get:

{ errors: 
   [ { domain: 'global',
       reason: 'required',
       message: 'Missing required field: member' } ],
  code: 400,
  message: 'Missing required field: member' }

I've googled the error and found questions like this, this and a few other unhelpful results.

I checked and it's definitely not a missing scope nor permissions.

#!/usr/bin/python
import httplib2
import json
from oauth2client.client import SignedJwtAssertionCredentials
from urllib import urlencode


def get_group_members(group):
    url = 'https://www.googleapis.com/admin/directory/v1/groups/{}/members'.format(group['email'])
    return call_google_api("GET", url)


def add_group_member(group, payload=False):
    url = 'https://www.googleapis.com/admin/directory/v1/groups/{}/members'.format(group)
    return call_google_api("POST", url, payload)


def call_google_api(method, url, payload=False):
    content = {}
    try:
        http = get_conn()
        if payload:
            (resp, content) = http.request(uri=url, method=method, body=urlencode(payload))
        else:
            (resp, content) = http.request(uri=url, method=method)
    except Exception as e:
        print "Failed to post request to [{}] due to: {}".format(url, e)
    return json.loads(content)

def get_conn():
    client_email = get_client_email_from_db()    
    with open(get_private_key_filename()) as f:
        private_key = f.read()

    oauth_scope = ['https://www.googleapis.com/auth/admin.directory.group.member', 
                  'https://www.googleapis.com/auth/admin.directory.group',
    ]

    credentials = SignedJwtAssertionCredentials(client_email, private_key, oauth_scope, sub='[email protected]')
    http = httplib2.Http()
    return credentials.authorize(http)


if __name__ == '__main__':
    payload = {
        "email": "[email protected]",
        "role": "MEMBER",
    }
    print "\n ---------------------------------- \n"
    print "calling add_group_member('[email protected]', '[email protected]')"
    res = add_group_member("[email protected]", payload)
    print "\n ---------------------------------- \n"

Comment:
I managed to achieve what I wanted by using the sdk apiclient.discovery.build, but still - I'm curious, what's the issue and if it can be solved.

Debugging the request:

connect: (www.googleapis.com, 443)
send: 'POST /admin/directory/v1/groups/[email protected]/members HTTP/1.1\r\nHost: www.googleapis.com\r\nContent-Length: 38\r\ncontent-type: application/json\r\naccept-encoding: gzip, deflate\r\nauthorization: Bearer ya29.RAFzf3hyxvP0LuR4VdpqKr_dD0WzOcvXjn4eWV5Em6xJDissi4ieOZ2ZBRMOP-WLhvTrecBxgF_6sznc1GKSWHanvgYTh_EzcilsAN0f5jOiiMahOadG2v5ixBPL9GcqebRdz_kQc1y2iQ\r\nuser-agent: Python-httplib2/0.9 (gzip)\r\n\r\nrole=MEMBER&email=alfasi%40xxxx.com'
reply: 'HTTP/1.1 400 Bad Request\r\n'
header: Vary: Origin
header: Vary: X-Origin
header: Content-Type: application/json; charset=UTF-8
header: Content-Encoding: gzip
header: Date: Sat, 28 Mar 2015 23:14:47 GMT
header: Expires: Sat, 28 Mar 2015 23:14:47 GMT
header: Cache-Control: private, max-age=0
header: X-Content-Type-Options: nosniff
header: X-Frame-Options: SAMEORIGIN
header: X-XSS-Protection: 1; mode=block
header: Server: GSE
header: Alternate-Protocol: 443:quic,p=0.5
header: Transfer-Encoding: chunked

Upvotes: 2

Views: 2956

Answers (2)

Sayali
Sayali

Reputation: 366

If you are trying to add a user to a group the first time, the role must be MEMBER. If it is anything other than that it gives you this error - Missing required field: member.

So first add the user as MEMBER and then specify any other role.

Upvotes: 0

lossleader
lossleader

Reputation: 13495

Since google APIs use (only?) JSON encoding, your post data is not being parsed into the needed member object. You are already loading json for the response, so you should just need to change the encoding, and optionally indicate it explicitly:

 if payload:
        (resp, content) = http.request(uri=url, method=method, body=urlencode(payload))
 # becomes:   
 if payload:
        (resp, content) = http.request(uri=url, method=method, body=json.dumps(payload), headers={'Content-type':'application/json'})

Upvotes: 3

Related Questions