Passing diffrent time slots in same field Django Rest framework - django-rest-framework

I want to send 3 diffrent time slots in a field ,But do not getting the diffrent slots,but getting error-->"message": "JSON parse error - Expecting property name enclosed in double quotes: line 3 column 9 (char 27)",
models.py
class Slot(models.Model):
time=models.TimeField(auto_now=False, auto_now_add=False,null=True,blank=True)
def __str__(self):
return str(self.time)
views.py
class Available(viewsets.ViewSet):
def create(self, request):
try:
data=request.data
timings=data.get('schedule')
for i in range(3):
time_obj=Slot()
time_obj.time=timings[i]['time']
time_obj.save()
return Response({"message":"Data delivered","success": True}, status=status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
postman response
{
"schedule":{
{
"time":"12:00"
},
{
"time":"12:10"
},
{
"time":"15:00"
}
}
}

looks like the data sent is not valid JSON it should be something like
{
"schedule":[
{
"time":"12:00"
},
{
"time":"12:10"
},
{
"time":"15:00"
}
]
}

Related

pytest json.decoder.JSONDecodeError

List item
Hi,
I need to pytest this function
def lambda_handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
But it failed by json error
def test_lambda_handler():
event = {
"Records": [
{
"Sns" : { "Message" : "test" }
}
]
}
response = fw_init.lambda_handler( event,"")
JSONDecodeError("Expecting value", s, err.value) from None
E json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Function loads() deserializes JSON from string. You trying to decode "Message" field value as JSON.
lambda_handler function's first argument is a JSON-formatted string, according to AWS documentation.
You need to pass an serialized data to lambda_handler function:
response = fw_init.lambda_handler(json.dumps(event) ,"")
In function lambda_handler() you need to deserialize data first, and then get field value:
def lambda_handler(event, context):
data = json.loads(event)
message = data['Records'][0]['Sns']['Message']

Response cards not displaying in website-lex

I have created Lex Chatbot and developed a website and integrated this Chatbot. Its working fine.But response cards in the form of buttons are not showing up.I got to know that I have to invoke it from lambda function.So I included the response card code .It works ,but after displaying the buttons it goes back and asks the first slot value again.I dont know where I am wrong
Here is the expected conversation.
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium (in form of buttons)
User clicks on low
Lex:Thanks,your ticket has been raised(expected)
What happens:
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium
User clicks on low
Lex:Please provide me your eid(goes back and asks the first slot value)
Here is my code:
import json
import logging
import re
import http.client
import mimetypes
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def elicit_slot_response(output_session_attributes,intent_name,slot_to_elicit,message):
responses= {
'dialogAction': {
'type': 'ElicitSlot',
'slottoElicit':'slot_to_elicit',
'message': {
'contentType': 'PlainText',
'content': message
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
]
}
}
}
return responses
def close():
val= {
"dialogAction":
{
"fulfillmentState":"Fulfilled",
"type":"Close",
"message":
{
"contentType":"PlainText",
"content":"Hey your ticket has been raised"
}
}
}
print(val)
return val
def lambda_handler(event, context):
val = ""
slots = event['currentIntent']['slots']
empidemployee= event['currentIntent']["slots"]["empidemployee"]
latestdesc= event['currentIntent']["slots"]["latestdesc"]
latestimpact= event['currentIntent']["slots"]["latestimpact"]
output_session_attributes = event['sessionAttributes'] if event['sessionAttributes'] is not None else {}
elicit_slot_response(output_session_attributes,'latestdetails','latestimpact',"impact")
val=close()
return val
The conversation flow restarts because in the ElicitSlot response from the Lambda function containing the response cards, you are not returning the slots parameter which would contain the slot values already taken as an input from the user.
So, include the slots parameter in the response the value for which could be event['currentIntent']['slots'].

Returning a Float in Graphene after querying DB

I am using some example code to return a list of fields and all is working for my Data Models. However I want to take an input, query the db, do a calculation and return a single number back. Everything works, bar getting the output to the end user.
class Query(graphene.ObjectType):
growth = graphene.Float(id=graphene.String())
def resolve_growth(self, info, id):
records = list(Model.objects.filter(id=id).order_by('date'))
## do calculation
return calculation
I get the following message in GraphiQL
{
"errors": [
{
"message": "Field \"growth\" of type \"Float\" must not have a sub selection.",
"locations": [
{
"line": 1,
"column": 32
}
]
}
]
}
I am making the following query on the client side using graphiQL:
{growth(id: "AAN") }
but this gets morphed into by the front end:
{growth(id: "AAN") {
id
} }
In the end I solved this by returning an Object.

How I can return my custom json file instead of default json file that generates spring boot?

I have a rest controller for authorization:
#RestController
class AuthController {
#PostMapping("/sign-up")
fun signUp(#RequestBody signUpRequest: SignUpRequest): ResponseEntity<String> {
some code here..
}
}
The signUp method gets SignUpRequest model as a request body. SignUpRequest model is:
enum class Role {
#JsonProperty("Student")
STUDENT,
#JsonProperty("Tutor")
TUTOR
}
data class SignUpRequest(
val role: Role,
val email: String,
val password: String
)
When I make /sign-up post request with JSON:
{
"role": "asdf",
"email": "",
"password": ""
}
It returns me an answer that were generated by spring boot:
{
"timestamp": "2020-02-12T05:45:42.387+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `foo.bar.xyz.model.Role` from String \"asdf\": not one of the values accepted for Enum class: [Student, Tutor]\n at [Source: (PushbackInputStream); line: 3, column: 10] (through reference chain: foo.bar.xyz.model.SignUpRequest[\"role\"])",
"path": "/sign-up"
}
Question is: How I can return my custom JSON instead of that default generated JSON?
I want to return my custom JSON, like:
{
"result": "Invalid user data are given",
"errors": [
{
"fieldName": "ROLE",
"text": "Given role does not exist"
},
{
"fieldName": "EMAIL",
"text": "EMAIL is empty"
}
]
}
I suggest you to create ErrorContrller that generates custom json map as response. Then when you will catch an error in sign-up method, call ErrorContrllers method.
You can find info from this link
Finally I found out a solution. You should create a class that annotates #ControllerAdvice, and make a method that annotates #ExceptionHandler.
#ControllerAdvice
class HttpMessageNotReadableExceptionController {
#ExceptionHandler(HttpMessageNotReadableException::class)
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
fun handleException(
exception: HttpMessageNotReadableException
): PostSignUpResponseError {
val errors = mutableListOf<PostSignUpResponseErrorItem>()
errors.add(
PostSignUpResponseErrorItem(
fieldNamePost = "Role",
text = "Given role does not exist"
)
)
return PostSignUpResponseError(
result = "Invalid user data are given",
errors = errors
)
}
}
where PostSignUpResponseErrorItem and PostSignUpResponseError are:
data class PostSignUpResponseError(
val result: String,
val errors: List<PostSignUpResponseErrorItem>
)
class PostSignUpResponseErrorItem(
val fieldNamePost: PostSignUpRequestFieldName,
val text: String
)
Anyway, I still don't know how to attach this thing to a certain PostMapping method.

How to return customized JSON response for an error in graphene / django-graphene?

I want to add status field to error response, so instead of this:
{
"errors": [
{
"message": "Authentication credentials were not provided",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"viewer": null
}
}
It should be like this:
{
"errors": [
{
"status": 401, # or 400 or 403 or whatever error status suits
"message": "Authentication credentials were not provided",
"locations": [
{
"line": 2,
"column": 3
}
]
}
],
"data": {
"viewer": null
}
}
I found out that I only can change message by raising Exception inside resolver: raise Error('custom error message'), but how to add field?
Code example:
class Query(UsersQuery, graphene.ObjectType):
me = graphene.Field(SelfUserNode)
def resolve_me(self, info: ResolveInfo):
user = info.context.user
if not user.is_authenticated:
# but status attr doesn't exist...
raise GraphQLError('Authentication credentials were not provided', status=401)
return user
Update the default GraphQLView with the following:
from graphene_django.views import GraphQLView as BaseGraphQLView
class GraphQLView(BaseGraphQLView):
#staticmethod
def format_error(error):
formatted_error = super(GraphQLView, GraphQLView).format_error(error)
try:
formatted_error['context'] = error.original_error.context
except AttributeError:
pass
return formatted_error
urlpatterns = [
path('api', GraphQLView.as_view()),
]
This will look for the context attribute in any exceptions raised. If it exists, it'll populate the error with this data.
Now you can create exceptions for different use cases that populate the context attribute. In this case you want to add the status code to errors, here's an example of how you'd do that:
class APIException(Exception):
def __init__(self, message, status=None):
self.context = {}
if status:
self.context['status'] = status
super().__init__(message)
You'd use it like this:
raise APIException('Something went wrong', status=400)
I didn't found a way to solve your problem int the way that you propose, otherwise i extend the LoginRequiredMixin class like this:
class LoginRequiredMixin:
def dispatch(self, info, *args, **kwargs):
if not info.user.is_authenticated:
e = HttpError(HttpResponse(status=401, content_type='application/json'), 'Please log in first')
response = e.response
response.content = self.json_encode(info, [{'errors': [self.format_error(e)]}])
return response
return super().dispatch(info, *args, **kwargs)
class PrivateGraphQLView(LoginRequiredMixin, GraphQLView):
schema=schema
and in your url:
from django.views.decorators.csrf import csrf_exempt
from educor.schema import PrivateGraphQLView
url(r'^graphql', csrf_exempt(PrivateGraphQLView.as_view(batch=True)))
you can't see the status with the graphiql but in your client you can get it in the headers or you could modify this line to add in the response response.content = self.json_encode(info, [{'errors': [self.format_error(e)]}])
. Hope it helps anyway i'll leave you another possible solution https://github.com/graphql-python/graphene-django/issues/252

Resources