- Notifications
You must be signed in to change notification settings - Fork302
-
Recommendations from the JSON:API specsJSON:API defines the following to handle async processing for long running tasks:
My implementation to handle long running create endpointTo follow that recommendation from the json:api specs if implemented it as following: Long running create endpointfromdjango_celery_results.modelsimportTaskResultfromrest_framework_json_api.viewsimportModelViewSetclassOgcServiceViewSet(ModelViewSet):queryset=OgcService.objects.all()serializer_classes= {'default':OgcServiceSerializer,'create':OgcServiceCreateSerializer }filterset_fields= {'id': ('exact','lt','gt','gte','lte','in'),'title': ('icontains','iexact','contains'), }search_fields= ('id','title',)defget_serializer_class(self):returnself.serializer_classes.get(self.action,self.serializer_classes['default'])defcreate(self,request,*args,**kwargs):serializer=self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)task=build_ogc_service.delay(data=serializer.data)task_result,created=TaskResult.objects.get_or_create(task_id=task.id)serialized_task_result=TaskResultSerializer(task_result)serialized_task_result_data=serialized_task_result.data# meta object is None... we need to set it to an empty dict to prevend uncaught runtime exceptionsmeta=serialized_task_result_data.get("meta",None)ifnotmeta:serialized_task_result_data.update({"meta": {}})headers=self.get_success_headers(serialized_task_result_data)returnResponse(serialized_task_result_data,status=status.HTTP_202_ACCEPTED,headers=headers)defget_success_headers(self,data):try:return {'Content-Location':str(data[api_settings.URL_FIELD_NAME])}except (TypeError,KeyError):return {} Create serializer with different field setclassOgcServiceCreateSerializer(ModelSerializer):# TODO: implement included serializer for ServiceAuthentication# included_serializers = {# 'auth': ServiceAuthentication,# }classMeta:model=OgcServicefields= ("get_capabilities_url", ) TaskResult serializerfromdjango_celery_results.modelsimportTaskResultfromregistry.models.jobsimportRegisterOgcServiceJobfromrest_framework_json_api.serializersimportModelSerializerclassTaskResultSerializer(ModelSerializer):classMeta:model=TaskResultfields="__all__" ResponseThe create enpoint is creating the celery job fine and response with the content like bellow: Response Body{"data": {"type":"OgcService","id":"8","attributes": {"task_id":"23e945e2-4c63-45bf-a76d-b64062db930e","task_name": null,"task_args": null,"task_kwargs": null,"status":"PENDING","worker": null,"content_type":"","content_encoding":"","result": null,"date_created":"2021-11-22T09:34:11.940341+01:00","date_done":"2021-11-22T09:34:11.940404+01:00","traceback": null,"meta": {} } }} Response headersallow: GET,POST,HEAD,OPTIONS content-encoding: gzip content-language: en content-length: 238 content-type: application/vnd.api+json referrer-policy: same-origin server-timing: SQLPanel_sql_time;dur=3.191709518432617;desc="SQL 2 queries" vary: Accept-Language,Cookie,Accept-Encoding,Origin x-content-type-options: nosniff x-frame-options: DENY Quesion
|
BetaWas this translation helpful?Give feedback.
All reactions
Replies: 2 comments 4 replies
-
I did not notice before that there is a recommendation from JSON:API spec on async calls... Great!
classOgcServiceCreateSerializer:classMeta:resource_name='TaskResult'
|
BetaWas this translation helpful?Give feedback.
All reactions
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
-
That did not properly work. I defined the {"errors": [ {"detail":"The resource object's type (OgcService) is not the type that constitute the collection represented by the endpoint (TaskResult).","status":"409","source": {"pointer":"/data" },"code":"error" } ]} on given POST data: {"data": {"attributes": {"get_capabilities_url":"http://geo5.service24.rlp.de/wms/karte_rp.fcgi?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities"},"relationships": {"owned_by_org": {"data": {"id":"b2fdc463-87cb-4deb-b39b-187f7616d1df","type":"Organization"}}},"type":"OgcService"}} This is correct, causeJSON:API spec defines the following:
But i did not find a constraint in the JSON:API spec that does not allow on a endpoint to response with a different resource object type ( So for my request the response looks like (with mismatching resource object type) : {"data": {"type":"OgcService","id":"9","attributes": {"task_meta": null,"task_id":"d8146e14-d1ef-46d5-a6d2-be0de7017703","task_name": null,"task_args": null,"task_kwargs": null,"status":"PENDING","worker": null,"content_type":"","content_encoding":"","result": null,"date_created":"2021-11-24T09:12:35.056767+01:00","date_done":"2021-11-24T09:12:35.056860+01:00","traceback": null },"links": {"self":"http://testserver/api/v1/registry/task-results/9/" } }} Here is the link to the current implemented code:https://github.com/mrmap-community/mrmap/blob/a215b1c11bfff1f17d13c27d3e7b3ca88c3e3f87/backend/registry/api/views/service.py#L108
OK - i understood. classWebMapServiceSerializer(ModelSerializer):url=HyperlinkedIdentityField(view_name='registry:taskresult-detail', )classMeta:model=WebMapServicefields="__all__" I struggled a bit with the view_name, cause i forgot to pass the app_name as well. |
BetaWas this translation helpful?Give feedback.
All reactions
-
True this error message makes sense. If we wanna support this async recommendation we properly would need a special case when response status code is 202 which than also handles |
BetaWas this translation helpful?Give feedback.
All reactions
-
I think the handling of the classJSONRenderer(renderers.JSONRenderer): ...defrender(self,data,accepted_media_type=None,renderer_context=None):ifserializerisnotNone:# Extract root meta for any type of serializerjson_api_meta.update(self.extract_root_meta(serializer,serializer_data))ifgetattr(serializer,"many",False): ...else: ...ifresponse.status_code==202:# handle async processing as recommended https://jsonapi.org/recommendations/#asynchronous-processingresource_name=utils.get_resource_type_from_serializer(serializer)response.headers.update({'Content-Location':serializer_data[api_settings.URL_FIELD_NAME]})resource_instance=serializer.instancejson_api_data=self.build_json_resource_obj(fields,serializer_data,resource_instance,resource_name,serializer,force_type_resolution, ) |
BetaWas this translation helpful?Give feedback.
All reactions
-
Hmm not so sure. During parsing wouldn't this still lead to the same error as when |
BetaWas this translation helpful?Give feedback.
All reactions
-
Additionally as a workaround what you could do is set |
BetaWas this translation helpful?Give feedback.