Dialogflow API V2 largeImage for MediaObject not working - node.js

I recently switched from the V1 to V2 for dialogflow and I'm updating my webhook.
I use mediaObjects with large Images in my agent as a personal taste.
Unfortunately I can't seem to make it work for the V2.
My current code for the media object is this:
conv.ask(new MediaObject({
name: 'Name',
largeImage: new Image({
url: 'https://[...].jpg',
alt: 'alternative'
}),
url: 'https://[...].mp3',
description: 'description'
}));
As you can see, I used the largeImage field, as I found it in the JSON section of Google's example . As the documentation is inexistant, I'm checking the node.js library for information and I verified that the largeImage field extends the Image interface so it should be correct.
It works when I switch largeImage for Icon but I don't like it.
My JSON response is like this:
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "text"
}
},
{
"mediaResponse": {
"mediaType": "AUDIO",
"mediaObjects": [
{
"contentUrl": "https://[...].mp3",
"description": "description",
"name": "name"
}
]
}
}
],
"suggestions": [
{
"title": "Not yet implemented"
}
]
},
"userStorage": "{\"data\":{}}"
}
}
For some reason the largeImage field doesn't appear in my JSON but there isn't any error appearing anywhere.

Some of the APIs in JSON do not match the Node.js parameters. For example, largeImage in JSON is actually image in the MediaObjectOptions definition.

Related

Swagger Nest.js ValidationPipe ApiBadRequestResponse

👋I just started playing around with Swagger and everything is amazing. I was able to document all API in an hour or so but I got stuck solving one last issue.
How can I tell swagger to show ApiBadRequestResponse in the format below?
#ApiOkResponse({
type: User,
})
#ApiBadRequestResponse({
type: {
error: String,
message: ValidationError[]
}
})
#Post('/signup')
signUp(
#Body(ValidationPipe) authCredentialsDto: CredentialsDTO
): Promise<User> {
return this.userService.signUp(authCredentialsDto)
}
From what I understand swagger doesn't know how to work with interfaces instead I have to use classes. Is there a simple way to document bad request response triggered by ValidationPipe. This is all native #nestjs behavior so I would assume there must be an easy solution.
This is what gets actually returned from API:
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"target": {
"username": "somename",
"password": "****"
},
"value": "****",
"property": "password",
"children": [], // ValidationError[]
"constraints": {
"matches": "password too weak"
}
}
]

How to get Session Entities to work as part of Dialogflow detect intent

I have an Entity that is supposed to be updated on a per-session basis with user-specific information. This had worked when I was using Dialogflow v1, and I thought it had worked with v2, but I'm now having significant problems with it.
I believe I am setting the Session Entity information correctly, but for the Intent that uses it, it only matches when a value from the Developer Entity is used.
How can I get it to use the Session Entity? Am I doing something wrong when updating it? Am I using the wrong Session ID? Is there a way I can better verify or test that I'm using the correct ID or that I'm updating the Entity correctly? Is this just a bug?
Documentation of everything follows.
The project is configured to use v2 and to allow for beta features, although I've tried this without the beta features as well.
There are only three Intents. A Fallback Intent to capture failures, a Welcome Intent that gets the welcome event, and the "entry" intent that is supposed to capture the entry code which should match the "code" Entity. All of them use a webhook for fulfillment.
The Fallback Intent
The Welcome Intent
The "entry" Intent
As shown in the "entry" Intent, it uses the "code" Entity, which is the only Developer Entity in the system
The code has most of the Dialogflow specific work in a separate module that uses the "dialogflow" module from npm to set the Session Entity. (Note this is different than the dialogflow-fulfillment module, which is used to handle fulfillment. I'm using the multivocal library for fulfillment, but that shouldn't matter.) (It also uses firebase functions to run on, but I don't think any of these are relevant.)
From the package.json:
"dependencies": {
"dialogflow": "^0.9.0",
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.2.0",
"multivocal": "^0.11.1"
},
This is imported as dialogflow, specifying the API version to use:
const dialogflow = require('dialogflow').v2beta1;
The functions I show below call envToConfig(env) which takes the environment (a multivocal concept that just stores relevant information, including the Dialogflow parent and certificate information) and returns the configuration that needs to be passed to dialogflow.SessionEntityTypesClient( config ). Given no errors are thrown in further calls, it appears to work correctly.
The makeEntityType( name, entityMap ) function takes a map of values to be used for the entities in a SessionEntityType and returns an object that will be used to build a full SessionEntityType. The name provided here is the display name.
function makeEntityType( name, entityMap ){
let ret = {
displayName: name,
entities: []
};
Object.keys( entityMap ).map( key => {
let val = entityMap[key];
let entity = {
value: key,
synonyms: [key, ...val]
};
ret.entities.push( entity );
});
return ret;
}
exports.makeEntityType = makeEntityType;
The result from this is passed to setSessionEntity( env, entityType ) along with the multivocal environment, which contains some information we use in the session. It makes sure the name and entityOverrideMode are set correctly in the entityType and then tries to create it. I've tried using PATCH as well, and it behaves the same way. It also does a bunch of logging, that I'll show later when it runs to prove it actually works.
function setSessionEntity( env, entityType ){
const config = envToConfig( env );
const client = new dialogflow.SessionEntityTypesClient( config );
let parent = env.dialogflow.parent;
if( entityType.displayName && !entityType.name ){
entityType.name = `${parent}/entityTypes/${entityType.displayName}`;
}
if( !entityType.entityOverrideMode ){
entityType.entityOverrideMode = 'ENTITY_OVERRIDE_MODE_OVERRIDE';
}
console.log('setSessionEntity parent',parent);
const request = {
parent: parent,
sessionEntityType: entityType
};
console.log('setSessionEntity request',JSON.stringify(request,null,1));
return client.createSessionEntityType( request )
.then( create => {
console.log('setSessionEntity created',JSON.stringify(create,null,1));
return Promise.resolve( env );
})
.catch( err => {
console.error('setSessionEntity problem creating',err);
return Promise.resolve( env );
})
}
exports.setSessionEntity = setSessionEntity;
For debugging, I also have a function that lists the session entities:
function listSessionEntities( env ){
let parent = env.dialogflow && env.dialogflow.parent;
console.log('listSessionEntities parent', parent);
if( !parent ){
return Promise.resolve( env );
}
const config = envToConfig( env );
const client = new dialogflow.SessionEntityTypesClient( config );
const request = {
parent: parent
};
return client.listSessionEntityTypes(request)
.then( result => {
console.log('listSessionEntities', JSON.stringify(result,null,1));
})
.catch( err => {
console.log('listSessionEntities err', err);
})
.then( () => Promise.resolve( env ) );
}
exports.listSessionEntities = listSessionEntities;
The code that calls this imports it as Dialogflow:
const Dialogflow = require('./dialogflow');
As part of all the webhook calls, the listSessionEntities() function is called before any specific handler is:
function debugSessionEntities( env ){
return Dialogflow.listSessionEntities( env );
}
When the Welcome Intent is triggered, it sets the "code" Session Entity to have two new types that should override the type that was defined in the "code" Developer Entity:
function handleWelcome( env ){
const entityType = Dialogflow.makeEntityType('code',{
'alpha': [],
'bravo': []
});
return Dialogflow.setSessionEntity( env, entityType )
.then( env => Multivocal.handleDefault( env ) );
}
When I run this through the simulator, it doesn't pick up on the Session Entity Types that are set, but do still respond to the Developer Entity Type. (Using a real device works the same way.)
In the simulator, this is what it reports in the Request tab for the Welcome Intent:
{
"responseId": "55a9eb06-ce05-48f9-8a56-b993fa512aee",
"queryResult": {
"queryText": "GOOGLE_ASSISTANT_WELCOME",
"action": "multivocal.welcome",
"parameters": {},
"allRequiredParamsPresent": true,
"fulfillmentText": "Hello! How can I help you?",
"fulfillmentMessages": [
{
"text": {
"text": [
"Greetings! How can I assist?"
]
}
}
],
"outputContexts": [
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/google_assistant_welcome"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_screen_output"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_audio_output"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_account_linking"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/google_assistant_input_type_keyboard"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_media_response_audio"
},
{
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/contexts/actions_capability_web_browser"
}
],
"intent": {
"name": "projects/session-test-XXXXX/agent/intents/ca79c951-4d75-4b2b-acd4-7dac2f81856e",
"displayName": "welcome"
},
"intentDetectionConfidence": 1,
"languageCode": "en-us"
},
"originalDetectIntentRequest": {
"source": "google",
"version": "2",
"payload": {
"isInSandbox": true,
"surface": {
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.ACCOUNT_LINKING"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"requestType": "SIMULATOR",
"inputs": [
{
"rawInputs": [
{
"query": "Talk to my test app",
"inputType": "KEYBOARD"
}
],
"intent": "actions.intent.MAIN"
}
],
"user": {
"userStorage": "{\"UserId\":\"ABwppHHd40lIZ1o0bRERAKlHNtNcS2qFtz7NbRQnb31AQDFuV41VPFQivXwwpQGtv_5SlsZNp0N3kxalIIXXXXXX\",\"NumVisits\":1}",
"lastSeen": "2019-05-18T19:12:38Z",
"locale": "en-US",
"userId": "ABwppHHd40lIZ1o0bRERAKlHNtNcS2qFtz7NbRQnb31AQDFuV41VPFQivXwwpQGtv_5SlsZNp0N3kxalIIXXXXXX"
},
"conversation": {
"conversationId": "ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX",
"type": "NEW"
},
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
}
]
}
]
}
},
"session": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX"
}
Most notable from that is the session attribute set at the bottom from that. The code uses this as the parent and session values when building the
The request objects for the other two Intents are similar, and all have the same value for session. None of the response objects are notable in any way.
When the Welcome Intent is triggered, the call to listSessionEntities(), unsurprisingly, shows there aren't any yet:
info: listSessionEntities parent projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX
info: listSessionEntities [
[],
null,
null
]
The parent appears to have the correct value from the session however.
When the handler for the Welcome Intent goes and creates the Session Entity, things appear to work ok:
info: setSessionEntity request {
"parent": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX",
"sessionEntityType": {
"displayName": "code",
"entities": [
{
"value": "alpha",
"synonyms": [
"alpha"
]
},
{
"value": "bravo",
"synonyms": [
"bravo"
]
}
],
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
"entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
}
}
info: setSessionEntity created [
{
"entities": [
{
"synonyms": [
"alpha"
],
"value": "alpha"
},
{
"synonyms": [
"bravo"
],
"value": "bravo"
}
],
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
"entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
},
null,
null
]
The parent appears to be the same as the session, and the name appears to follow the correct format, including the additional part that has the "/entityTypes/" followed by the display name.
When I try calling it with the code "alpha", which should trigger the "entry" Intent, it instead triggers the Fallback Intent. The call to listSessionEntities() seems to show the "code" Entity with the Entity Types we expect, even tho there was no match for "alpha".
info: listSessionEntities parent projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX
info: listSessionEntities [
[
{
"entities": [
{
"synonyms": [
"alpha"
],
"value": "alpha"
},
{
"synonyms": [
"bravo"
],
"value": "bravo"
}
],
"name": "projects/session-test-XXXXX/agent/sessions/ABwppHFGTpcFtHOOo6ehQfKys9AnH14V5-RhzrNKsea6y6L5zgv4eN-j3IesfuqSsKMc7qRt1CAOhkUYA9XXXXXX/entityTypes/code",
"entityOverrideMode": "ENTITY_OVERRIDE_MODE_OVERRIDE"
}
],
null,
null
]
Again, everything looks correct. When I try it again with "zulu", it shows the same thing for the call to listSessionEntites(), but this time it matches the "entry" Intent, since "zulu" is one of the Entity Types for "code" that is defined as a Developer Entity.
This is where I am stuck. Everything looks correct. It looks like the Session Entity should be set correctly for this session. It looks like it should be using those values. But it never seems to do so.
What is going on? All help would be greatly appreciated. (Did you even read till the end of the question? If so - thank you! I know it's long, but wanted to be as complete as possible.)
This appears to be a bug - I've gotten feedback from other developers that they're seeing the same problem, sometimes on previously working code.
A bug has been opened at https://issuetracker.google.com/issues/133166381 to track the issue. Star it to indicate you have similar problems and to track progress.

No response returned and app gets down when requesting a sign in for Account Linking

Instantiating a SignIn using conv.ask() always fails. My action says no-response when sign-in flow is called and it leaves my app.
In my Firebase Functions log, the json below was spitted, which probably means that it is correctly called, but there is something wrong. I tried updating my Actions on Google console, cleared sign in setting in the Directory page, tested in some different accounts, cleared data to reset in my action app and as such. Needless to say, I set clientId inside the dialogflow class paramerter.
I totally have no idea for this. I have done many projects for Google Assistant apps which required SignIn Account Linking flow. But I encounter this strange behavior only for this project. What should I do? SDK verions is "actions-on-google": "^2.6.0".
Response {
"status": 200,
"headers": {
"content-type": "application/json;charset=utf-8"
},
"body": {
"payload": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.SIGN_IN",
"data": {
"#type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
"optContext": "For account creation"
}
},
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Please do sign in "
}
}
]
}
}
}
}
}
Inside conv.user 
{
"raw":{
"locale":"ja-JP",
"userId":"ABwppHGDYgpYn2waeaDyKoMZIqhg4ZxO56vXeAhs-43ZUC6VF3SdCvUGY3L1Vd08eTY_hRLfjrvp4"
},
"storage":{
},
"_id":"ABwppHGDYgpYn2waeaDyKoMZIqhg4ZxO56vXeAhs-43ZUC6VF3SdCvUGY3L1Vd08eTY_hRSfjrvp4",
"locale":"ja-JP",
"permissions":{
},
"last":{
},
"name":{
},
"entitlements":{
},
"access":{
},
"profile":{
}
}
// THIS SEEMS TO BE CALLED according to Firebase Functions Log
app.intent('StartSignIn', (conv) => {
conv.ask(new SignIn('For account creation'));
})
app.intent(INTENT.SignInIntent, (conv, params, signin) => {
console.log('INTENT.SignInIntent is called');
if (signin.status !== 'OK') {
conv.close(`failed`);
return;
}
conv.close('please wait');
});
UPDATE
I figured out the solution by making another folder and doing firebase init, and connected it to a new Firebase project. The main reason is unknown but it worked well by creating a new project.

Using the cloud functions emulator to test Dialogflow fulfillment locally

Is it possible to test your Dialogflow fulfillment webhook locally using the cloud functions emulator, and if so, how should I format the request?
I've read through all the documentation I can find, including the guide at https://firebase.google.com/docs/functions/local-emulator, and of particular interest was this previous question which seems to hit on a similar point:
Unit test Actions on Google Dialogflow locally
I am able to invoke my fulfillment function with the functions shell, however no matter how I attempt to format the body I can only ever seem to trigger my fallback intent or the error catching intent.
I can verify on the Actions on Google simulator that my webhook successfully responds with the default welcome intent when given the input "hello", but when using the same request JSON data as input to my function locally, I am directed to the fallback intent.
Is it the case that the functions emulator cannot perform the proper intent-matching locally and therefore always triggers the fallback intent, or am I simply not formatting my request right? Any help would be greatly appreciated!
Here is the invocation format which I am using, and the response from the shell:
firebase > fulfillment({method: 'POST',json: true,body:
require("project/collabrec/testData.json")});
Sent request to function.
firebase > info: User function triggered, starting execution
info: Fallback intent triggered.
info: Execution took 15 ms, user function completed successfully
RESPONSE RECEIVED FROM FUNCTION: 200, {
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "I didn't quite catch that. Could you say that again?"
}
}
]
}
}
}
}
Here is the testData.json content:
{
"user": {
"userId": "ABwppHFR0lfRsG_UM3NkvAptIkD2iUpIUNxFt-ia05PFuPajV6kRQKXu_H_ECMMe0lP_WcCsK64sH2MEIg8eqA",
"locale": "en-US",
"lastSeen": "2018-10-19T15:20:12Z"
},
"conversation": {
"conversationId": "ABwppHHerN4CIsBZiWg7M3Tq6NwlTWkfN-_zLIIOBcKbeaz4ruymv-nZ4TKr6ExzDv1tOzszsfcgXikgqRJ9gg",
"type": "ACTIVE",
"conversationToken": "[]"
},
"inputs": [
{
"intent": "actions.intent.TEXT",
"rawInputs": [
{
"inputType": "KEYBOARD",
"query": "hello"
}
],
"arguments": [
{
"name": "text",
"rawText": "hello",
"textValue": "hello"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
},
"isInSandbox": true,
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.WEB_BROWSER"
}
]
}
],
"requestType": "SIMULATOR"
}
And here is my cloud function webhook:
const {dialogflow, Image} = require('actions-on-google');
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const app = dialogflow();
app.catch((conv, error) => {
console.log("Error intent triggered.")
console.error(error);
conv.ask('Sorry, I ran into an error. Please try that again.');
});
app.fallback((conv) => {
console.log("Fallback intent triggered.")
conv.ask("I didn't quite catch that. Could you say that again?");
})
app.intent('Default Welcome Intent', (conv) => {
console.log("Welcome intent triggered.")
conv.ask("Welcome!!");
});
exports.fulfillment = functions.region('europe-west1').https.onRequest(app);
Using Node v8.1.4, and package versions:
"#google-cloud/common-grpc": "^0.9.0",
"#google-cloud/firestore": "^0.17.0",
"#google-cloud/functions-emulator": "^1.0.0-beta.5",
"actions-on-google": "^2.4.1",
"firebase-admin": "^6.0.0",
"firebase-functions": "^2.0.5"
The issue is that you're using the JSON that comes from the AoG Simulator, but this shows the JSON that AoG is sending to Dialogflow. Dialogflow processes this and sends your webhook a different JSON which includes the results of processing the AoG JSON and determining the intent, parameters, and other information.
What you are doing should work - if you have the Dialogflow JSON. You have a couple of ways to do this:
The most straighforward is to run your webhook on a place that can receive the POST from Dialogflow and look at the conv.request object, which should be able to give you the JSON you need.
If you're running the webhook on a local dev machine (as you suggest you are), I tend to start up an ngrok tunnel. The tunnel gives a public HTTPS server, which is very useful, and has the side effect of giving me a console that I can use to see exactly the contents of the request and response JSON.
Finally, you should be able to go into the project settings in Dialogflow and turn on Cloud Logging. The log includes the request that is sent to your webhook along with the response that you get from it.

Getting started with FortuneJS

Evening All,
I'm hoping that this is me making a school-boy error. Trying to 'get started' with fortuneJS but having an issue whilst trying to create a new resource.
So, I've setup fortune as described on their homepage. I've opted to use their JSON API plugin, again setup as per their repo.
I'm using Postman to test out the server I've created and I can create a 'user' resource no problem with the following:
{
"data": {
"type": "user",
"attributes": {
"name": "Andrew"
}
}
}
That works fine and I get a response as follows:
{
"data": {
"type": "users",
"id": "37446bbc",
"attributes": {
"name": "Andrew"
},
"relationships": {
"posts": {
"links": {
"self": "http://localhost:1337/users/37446bbc/relationships/posts",
"related": "http://localhost:1337/users/37446bbc/posts"
},
"data": []
}
},
"links": {
"self": "http://localhost:1337/users/37446bbc"
}
}
}
Now, I need to try and create the 'post' resource. Following the JSON API specification I'm posting the following payload:
{
"data": {
"type": "posts",
"attributes": {
"message": "This is my first post"
},
"relationships": {
"author": {
"data": { "type": "users", "id": "37446bbc" }
}
}
}
}
All I get back from that is:
{
"errors": [
{
"title": "Error",
"detail": "An internal server error occurred."
}
]
}
I've debugged by placing a console log of the 'error' on line 118 in node_modules/fortune/dist/lib/dispatch/index.js which shows this error:
[TypeError: Cannot set property 'user' of undefined]
Any advice or guidance you can offer would be greatly appreciated. Hopefully it's just me!
I'm using babel-node app.js to get this running. To save you time, I've thrown up the code onto a public repo
It seems that the actual error message needs to be relayed to the client. You can do so by attaching a catch to the HTTP listener:
const server = http.createServer((request, response) =>
fortune.net.http(store)(request, response)
.catch(error => console.log(error.stack)))
What I found when I recreated the steps was this:
Error: A related record for the field "author" was not found.
However, since it is a generic Error and not a typed error that Fortune uses internally, it is hidden from the client.
So by setting the correct value for the author id, it was able to create a record with that association successfully.
Future versions will be patched so that this informative error message gets shown.
The originally posted question works fine, the version of node was causing an error. Upgrading to v4.2.1 resolved the issue.

Resources