-
Notifications
You must be signed in to change notification settings - Fork 64
Developer's Guide
The OCL API is implemented as a series of modifications to the Django REST Framework. These modifications were necessary to allow for the nesting of resources, and are outlined below. This guide is intended to be used as a supplement to the Django REST Framework Quickstart Guide, and is structured in the same fashion.
Most CREATE and UPDATE serializers are implemented as standard rest_framework.serializers.Serializer classes. For these operations, the list of fields specified in the class definition describes the set of fields that may be set (or modified) by the corresponding operation. For most resource types, some subset of fields will be unmodifiable, so the UPDATE view will be distinct from the CREATE view. For example, consider:
class OrganizationUpdateSerializer(serializers.Serializer):
name = serializers.CharField(required=False)
company = serializers.CharField(required=False)
website = serializers.CharField(required=False)
which is distinct from:
class OrganizationCreateSerializer(serializers.Serializer):
id = serializers.CharField(required=True, validators=[RegexValidator(regex=NAMESPACE_REGEX)], source='mnemonic')
name = serializers.CharField(required=True)
company = serializers.CharField(required=False)
website = serializers.CharField(required=False)
because the id field is unmodifiable.
The next most-widely used serializer is the homegrown oclapi.serializers.HyperlinkedResourceSerializer. It is nearly identical to the REST Framework's rest_framework.serializers.HyperlinkedModelSerializer, except that it uses a different field type to render the identity ('url') field.
class HyperlinkedModelSerializer(ModelSerializer):
...
def get_default_fields(self):
fields = super(HyperlinkedModelSerializer, self).get_default_fields()
if self.opts.view_name is None:
self.opts.view_name = self._get_default_view_name(self.opts.model)
if 'url' not in fields:
url_field = HyperlinkedIdentityField(
view_name=self.opts.view_name,
lookup_field=self.opts.lookup_field
)
ret = self._dict_class()
ret['url'] = url_field
ret.update(fields)
fields = ret
return fields
Note that the HyperlinkedModelSerializer uses the REST Framework's rest_framework.relations.HyperlinkedIdentityField to render its 'url' field. This field type merely uses django.core.urlresolvers.reverse to generate a URL for the object in question, but this implementation of reversedoes not account for the nested of resources.
HyperlinkedResourceSerializer instead uses a HyperlinkedResourceIdentifyField:
class HyperlinkedResourceSerializer(serializers.Serializer):
...
def get_default_fields(self):
fields = super(HyperlinkedResourceSerializer, self).get_default_fields()
if self.opts.view_name is None:
self.opts.view_name = self._get_default_view_name(self.opts.model)
if 'url' not in fields:
url_field = HyperlinkedResourceIdentityField(
view_name=self.opts.view_name,
)
ret = self._dict_class()
ret['url'] = url_field
ret.update(fields)
fields = ret
return fields
HyperlinkedResourceIdentityField uses oclapi.utils.reverse_resource to generate the resource URL, which, unlike django.core.urlresolvers.reverse, does account for resource nesting.
The OrganizationDetailSerializer is an example of a HyperlinkedResourceSerializer:
class OrganizationDetailSerializer(HyperlinkedResourceSerializer):
type = serializers.CharField(source='resource_type')
uuid = serializers.CharField(source='id')
id = serializers.CharField(source='mnemonic')
name = serializers.CharField()
company = serializers.CharField()
website = serializers.CharField()
members = serializers.IntegerField(source='num_members')
publicSources = serializers.IntegerField(source='public_sources')
createdOn = serializers.DateTimeField(source='created_at')
updatedOn = serializers.DateTimeField(source='updated_at')
So, in addition to the fields listed above, OrganizationDetailSerializer will use HyperlinkedResourceIdentityField (which uses oclapi.utils.reverse_resource) to render the resource URL for the organization in question.
HyperlinkedResourceSerializer is one example of a serializer that renders a derived field ('url') in addition to the set of declared fields. Here are some others:
A sub-resource is a resource that exists only within the context of another resource. For example, a Source only exists within the context of a User or an Organization. That User or Organization is referred to as the Source's parent, or owner.
A HyperlinkedSubResourceSerializer is used to render the detail view of a sub-resource. It inherits from HyperlinkedResourceSerializer, so it injects a 'url' field, but in addition to that, it also derives and renders an 'ownerUrl' field, which is the resource URL for the sub-resource's parent.
class HyperlinkedSubResourceSerializer(HyperlinkedResourceSerializer):
def get_default_fields(self):
default_fields = super(HyperlinkedSubResourceSerializer, self).get_default_fields()
parent_resource = self.object.parent if hasattr(self.object, 'parent') else self.object.versioned_object.parent
default_fields.update({
'ownerUrl': HyperlinkedResourceOwnerField(view_name=self._get_default_view_name(parent_resource))
})
return default_fields
Overview
Resources
Import / Export
- CSV Import
- Bulk Import
- Org/Source Import
- Export API
- Subscriptions
- Subscription Client Testing Process
- OpenMRS to OCL Mapping
Troubleshooting & Operations
- Data integrity checks
- Maintaining OCLAPI's Docker containers
- Maintaining MongoDB and Solr
- How to check logs
- NewRelic monitoring setup
- Configuration changes to make tests and import job run faster
- Accessing Solr UI Remotely
- Data Backup and Restore
- SSL Configuration
- Flower
- Switching to Maintenance Mode on Production Server
- Docker networking and Security
Other