def _get_fields_from_method(spore_method): fields = [] required_params = spore_method.get('required_params', []) path = spore_method.get('path') optional_params = spore_method.get('optional_params', []) for param in required_params: if re.search(r'\{%s\}' % param, path): location = 'path' else: location = 'query' fields.append( Field(name=param, required=True, location=location, description=spore_method.get('documentation', ''))) for param in optional_params: fields.append( Field(name=param, required=False, location='query', description=spore_method.get('documentation', ''))) return fields
def get_manual_fields(self, path, method): if method == "GET": return [] elif method == "POST": return [ Field('name'), Field('email'), ]
def get_manual_fields(self, path, method): if (method == "GET"): return [] elif method == "POST": return [ Field('id', description='user id'), Field('code', description='code from sso login') ]
def get_manual_fields(self, path, method): if method == "GET": return [] elif method == "PUT": return [ Field('id'), Field('token', description='sent via email'), Field('email') ]
class RateQuery(APIView): parser_classes = (JSONParser, XMLParser) schema = AutoSchema(manual_fields=[ Field("start", required=True, schema=coreschema.String()), Field("end", required=True, schema=coreschema.String()) ]) rate_handler = RateQueryHandler() def get(self, request): """Get the rate for a given date range This is the GET version which accepts query params Arguments: request {[type]} -- [description] Returns: integer -- the rate for the given range Responses: 200 -- OK 404 -- No rate found for range """ return self._handle_request(request.query_params) def post(self, request): """Get the rate for a given date range This is the POST equivalent that accepts a json/xml format Arguments: request {[type]} -- [description] Keyword Arguments: format {[type]} -- [description] (default: {None}) Returns: integer -- the rate for the given range Responses: 200 -- OK 404 -- No rate found for range """ return self._handle_request(request.data) def _handle_request(self, data): serializer = RateRequestSerializer(data=data) if not serializer.is_valid(): return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST) start_time = serializer.validated_data['start'] end_time = serializer.validated_data['end'] return self.rate_handler.handle_request(start_time, end_time)
def get_serializer_fields(self, path, method, view, version=None, method_func=None): """ Return a list of `coreapi.Field` instances corresponding to any request body input, as determined by the serializer class. """ if method in ('PUT', 'PATCH', 'POST'): location = 'form' else: location = 'query' serializer_class = self.get_serializer_class(view, method_func) if not serializer_class: return [] serializer = serializer_class() if isinstance(serializer, serializers.ListSerializer): return [ Field(name='data', location=location, required=True, schema=coreschema.Array()) ] if not isinstance(serializer, serializers.Serializer): return [] fields = [] for field in serializer.fields.values(): if field.read_only or isinstance(field, serializers.HiddenField): continue required = field.required and method != 'PATCH' # if the attribute ('help_text') of this field is a lazy translation object, force it to generate a string description = str(field.help_text) if isinstance( field.help_text, Promise) else field.help_text fallback_schema = self.fallback_schema_from_field(field) field = Field( name=field.field_name, location=location, required=required, schema=fallback_schema if fallback_schema else field_to_schema(field), description=description, ) fields.append(field) return fields
def get_schema_fields(self, view): return [ Field( name="name", location="query", required=False, type="string", description="book name lookup", ), Field( name="isbn", location="query", required=False, type="string", description="ISBN lookup", ), ]
def get_response_object(self, response_serializer_class, description): fields = [] serializer = response_serializer_class() nested_obj = {} for field in serializer.fields.values(): # If field is a serializer, attempt to get its schema. if isinstance(field, serializers.Serializer): subfield_schema = self.get_response_object( field.__class__, None)[0].get('schema') # If the schema exists, use it as the nested_obj if subfield_schema is not None: nested_obj[field.field_name] = subfield_schema nested_obj[ field.field_name]['description'] = field.help_text continue # Otherwise, carry-on and use the field's schema. fallback_schema = self.fallback_schema_from_field(field) fields.append( Field( name=field.field_name, location='form', required=field.required, schema=fallback_schema if fallback_schema else field_to_schema(field), )) res = _get_parameters(Link(fields=fields), None) if not res: if nested_obj: return { 'description': description, 'schema': { 'type': 'object', 'properties': nested_obj } }, {} else: return {}, {} schema = res[0]['schema'] schema['properties'].update(nested_obj) response_schema = {'description': description, 'schema': schema} error_status_codes = {} response_meta = getattr(response_serializer_class, 'Meta', None) for status_code, description in getattr(response_meta, 'error_status_codes', {}).items(): error_status_codes[status_code] = {'description': description} return response_schema, error_status_codes
class Parameters(object): """ Class that holds all parameter schemas """ api_key = Field( 'api-key', location='query', required=True, schema=String(description='API KEY for access healthsites api.'), ) page = Field( 'page', location='query', required=True, schema=Integer( description='A page number within the paginated result set.'), ) extent = Field( 'extent', location='query', required=False, schema=String( description='Extent of map that is used for filtering data. ' '(format: minLng, minLat, maxLng, maxLat)'), ) timestamp_from = Field( 'from', location='query', required=False, schema=Integer( description='Get latest modified data from this timestamp.'), ) timestamp_to = Field( 'to', location='query', required=False, schema=Integer( description='Get latest modified data from this timestamp.'), ) country = Field( 'country', location='query', required=False, schema=String(description='Filter by country'), ) output = Field( 'output', location='query', required=False, schema=String( description= 'Output format for the request. (json/xml/geojson, default: json)' ), )
def get_schema_fields(self, view): return [ Field( name="query", location="query", required=False, type="string", description="tag initials", ), ]
def get_serializer_fields(self, path, method, view, version=None): """ Return a list of `coreapi.Field` instances corresponding to any request body input, as determined by the serializer class. """ if method not in ('PUT', 'PATCH', 'POST'): return [] if not hasattr(view, 'serializer_class') and not hasattr( view, 'get_serializer_class'): return [] serializer_class = view.get_serializer_class() if hasattr(view, 'get_serializer_class') \ else view.serializer_class serializer = serializer_class() if isinstance(serializer, serializers.ListSerializer): return [ Field(name='data', location='body', required=True, schema=coreschema.Array()) ] if not isinstance(serializer, serializers.Serializer): return [] fields = [] for field in serializer.fields.values(): if field.read_only or isinstance(field, serializers.HiddenField): continue required = field.required and method != 'PATCH' field = Field( name=field.field_name, location='form', required=required, schema=field_to_schema(field), description=field.help_text, ) fields.append(field) return fields
def get_manual_fields(self, path, method): custom_fields = [] if method.lower() == "post": custom_fields.append( Field("message", required=True, location="form", description="message to send to other users")) return custom_fields
def get_manual_fields(self, path, method): custom_fields = [] if method.lower() == "post": custom_fields.append( Field("direction", required=True, location="form", description="direction to move", example="n")) return custom_fields
def get_manual_fields(self, path, method): """Example adding per-method fields.""" extra_fields = [] if method == 'POST': extra_fields = [ Field( 'username', required=True, location="form", ), Field( 'password', required=True, location="form", ) ] manual_fields = super().get_manual_fields(path, method) return manual_fields + extra_fields
def get_link(self, path, method, base_url): link = super().get_link(path, method, base_url) fields = [ Field('time_type', location='query', required=True, schema=coreschema.Enum(enum=['year', 'month'])), Field('time_value', location='query', required=True, schema=coreschema.String()), ] fields = tuple(fields) link = Link(url=link.url, action=link.action, encoding=link.encoding, fields=fields, description=link.description) document.Link() return link
def get_note(identifier): """ Return a Document object for a single note instance. """ note = notes[identifier] return Document( url='/' + identifier, title='Note', content={ 'description': note['description'], 'complete': note['complete'], 'edit': Link(action='put', fields=[Field(name='description'), Field(name='complete')]), 'delete': Link(action='delete') })
class GetUserDetailsView(generics.RetrieveAPIView): permission_classes = [permissions.IsAuthenticated] schema = ManualSchema(fields=[ Field("employee_id", required=True, location='query', type='integer', description='Employee ID id of user') ]) def get(self, request, *args, **kwargs): try: if request.query_params['employee_id'] == 'me': employee_id = self.request.user.employee_id else: employee_id = int(self.request.query_params['employee_id']) user = models.User.objects.get(employee_id=employee_id) except ValueError: return JsonResponse( { 'success': False, 'message': 'Invalid user id' }, status=400) except models.User.DoesNotExist: return JsonResponse( { 'success': False, 'error': 'User with this id does not exist' }, status=400) except MultiValueDictKeyError: return JsonResponse( { 'success': False, 'message': 'Parameter value "employee_id" is required' }, status=400) try: serializer = serializers.GetUserDetailInfoSerializer(user) return Response({ 'success': True, 'data': serializer.data }, status=status.HTTP_200_OK) except Exception: return JsonResponse( { 'success': False, 'message': 'Error occurred in getting user data!' }, status=500)
def test_get_with_path_parameter(monkeypatch, http): def mockreturn(self, request): insert = request.url.encode('utf-8') return MockResponse(b'{"_type": "document", "example": "' + insert + b'"}') monkeypatch.setattr(requests.Session, 'send', mockreturn) link = Link(url='http://example.org/{user_id}/', action='get', fields=[Field(name='user_id', location='path')]) doc = http.transition(link, decoders, params={'user_id': 123}) assert doc == {'example': 'http://example.org/123/'}
def get_path_fields(self, path, method, view): """ Return a list of `coreapi.Field` instances corresponding to any templated path variables. """ model = getattr(getattr(view, 'queryset', None), 'model', None) fields = [] for variable in uritemplate.variables(path): if variable == 'version': continue title = '' description = '' schema_cls = coreschema.String kwargs = {} if model is not None: # Attempt to infer a field description if possible. try: model_field = model._meta.get_field(variable) except: model_field = None if model_field is not None and hasattr(model_field, 'verbose_name'): title = force_text(model_field.verbose_name) if model_field is not None and hasattr(model_field, 'help_text'): description = force_text(model_field.help_text) elif model_field is not None and hasattr( model_field, 'primary_key'): description = get_pk_description(model, model_field) if hasattr(view, 'lookup_value_regex' ) and view.lookup_field == variable: kwargs['pattern'] = view.lookup_value_regex elif isinstance(model_field, models.AutoField): schema_cls = coreschema.Integer field = Field(name=variable, location='path', required=True, schema=schema_cls(title=title, description=description, **kwargs)) fields.append(field) return fields
def get_notes(): """ Return the top level Document object, containing all the note instances. """ return Document( url='/', title='Notes', content={ 'notes': [get_note(identifier) for identifier in reversed(notes.keys())], 'add_note': Link(action='post', fields=[Field(name='description', required=True)]) })
def get_manual_fields(self, path, method): """Example adding per-method fields.""" extra_fields = [] if method == 'POST': extra_fields = [ Field( 'account', description="receptor account number.", location="form", ) ] manual_fields = super().get_manual_fields(path, method) return manual_fields + extra_fields
def get_link(route: Route) -> Link: """ Given a single route, return a Link instance containing all the information needed to expose that route in an API Schema. """ path, method, view = route view_signature = inspect.signature(view) uritemplate = URITemplate(path) description = _get_link_description(view) fields = [] for param in view_signature.parameters.values(): if param.annotation is inspect.Signature.empty: annotated_type = str else: annotated_type = param.annotation location = None required = False param_schema = _annotated_type_to_coreschema(annotated_type) if param.name in uritemplate.variable_names: location = 'path' required = True elif (annotated_type in primitive_types) or issubclass( annotated_type, schema_types): if method in ('POST', 'PUT', 'PATCH'): if issubclass(annotated_type, schema.Object): location = 'body' required = True else: location = 'form' else: location = 'query' if location is not None: field = Field(name=param.name, location=location, required=required, schema=param_schema) fields.append(field) return Link(url=path, action=method, description=description, fields=fields)
def get_response_object(self, response_serializer_class, description): fields = [] serializer = response_serializer_class() nested_obj = {} for field in serializer.fields.values(): if isinstance(field, serializers.Serializer): nested_obj[field.field_name] = self.get_response_object( field.__class__, None)[0]['schema'] nested_obj[field.field_name]['description'] = field.help_text continue fields.append( Field(name=field.field_name, location='form', required=field.required, schema=field_to_schema(field))) res = _get_parameters(Link(fields=fields), None) if not res: if nested_obj: return { 'description': description, 'schema': { 'type': 'object', 'properties': nested_obj } }, {} else: return {}, {} schema = res[0]['schema'] schema['properties'].update(nested_obj) response_schema = {'description': description, 'schema': schema} error_status_codes = {} response_meta = getattr(response_serializer_class, 'Meta', None) for status_code, description in getattr(response_meta, 'error_status_codes', {}).items(): error_status_codes[status_code] = {'description': description} return response_schema, error_status_codes
def test_mocking(self): content = { 'test': { 'post_data': Link(url='/post_data/', action='post', fields=[Field('data', location='body')]), } } schema = Document(title='test', content=content) mock.add(schema, ['test', 'post_data'], {"a": 1}) client = DjangoCoreAPIClient() doc = client.action(schema, ['test', 'post_data'], params={'data': { 'test': 'cat' }}) self.assertEqual(doc, {"a": 1})
def test_post_data(self): content = { 'test': { 'post_data': Link(url='/post_data/', action='post', fields=[Field('data', location='body')]), } } schema = Document(title='test', content=content) client = DjangoCoreAPIClient() doc = client.action(schema, ['test', 'post_data'], params={'data': { 'test': 'cat' }}) self.assertIsNotNone(doc)
def test_document_equality(doc): assert doc == { 'integer': 123, 'dict': { 'key': 'value' }, 'list': [1, 2, 3], 'link': Link(url='/', action='post', transform='inplace', fields=[ 'optional', Field('required', required=True, location='path') ]), 'nested': { 'child': Link(url='/123') } }
def get_link(self, path, method, base_url): link = super().get_link(path, method, base_url) # 无法指定bill_ids数组中的元素类型,这里元素定义为int但实际为str,无法处理... batch_del_fields = [ Field('bill_ids', location='form', required=True, schema=coreschema.Array(items=coreschema.Integer(), unique_items=True)) ] fields = link.fields if link.url == '/api/v1/bills/batch/' and method.lower() == 'delete': fields = tuple(batch_del_fields) link = Link(url=link.url, action=link.action, encoding=link.encoding, fields=fields, description=link.description) document.Link() return link
def doc(): return Document(url='http://example.org', title='Example', content={ 'integer': 123, 'dict': { 'key': 'value' }, 'list': [1, 2, 3], 'link': Link(url='/', action='post', transform='inplace', fields=[ 'optional', Field('required', required=True, location='path') ]), 'nested': { 'child': Link(url='/123') } })
] app = App(routes=routes) client = TestClient(app) expected = Schema( url='/schema/', content={ 'list_todo': Link(url='/todo/', action='GET', description='list_todo description', fields=[ Field(name='search', location='query', required=False, schema=coreschema.String()) ]), 'add_todo': Link(url='/todo/', action='POST', description='add_todo description\nMultiple indented lines', fields=[ Field(name='note', location='body', required=True, schema=coreschema.String()) ]), 'show_todo': Link(url='/todo/{ident}/', action='GET',
def get_manual_fields(self, path, method): extra_fields = [] if method == 'GET' and 'id' not in path: extra_fields = [ Field( 'active', required=False, location='query', schema=coreschema.String( description= 'Boolean, if set will only show bookables marked as "Active"' )), Field( 'mine', required=False, location='query', schema=coreschema.String( description= 'Boolean, if set will only show bookables for hosts with the current user as the owner' )), Field( 'mygroup', required=False, location='query', schema=coreschema.String( description= 'Boolean, if set will only show bookables for hosts assigned to one of the user\'s groups' )), Field('lab', required=False, location='query', schema=coreschema.String( description='Filter only those in lab ID')), Field('building', required=False, location='query', schema=coreschema.String( description='Filter only those in building ID')), Field( 'hw', required=False, location='query', schema=coreschema.String( description='Filter only those with HostHardware of ID' )), Field('htype', required=False, location='query', schema=coreschema.String( description='Filter only those in HostType of ID')), Field('lab', required=False, location='query', schema=coreschema.String( description='Filter only those in lab ID')), Field( 'nores', required=False, location='query', schema=coreschema.String( description= 'Boolean, if set will exclude bookables that are reserved' )), Field( 'free', required=False, location='query', schema=coreschema.String( description= 'Boolean, if set will only show bookables that are free to book now' )), ] manual_fields = super().get_manual_fields(path, method) return manual_fields + extra_fields