AWS Amplify: How custom Resolver? - aws-appsync

I'm learning to use AWS Amplify and need some guidance.
This is my schema.graphql file content (it's the default Queries):
type Blog #model {
id: ID!
name: String!
posts: [Post] #hasMany
}
type Post #model {
id: ID!
title: String!
blog: Blog #belongsTo
comments: [Comment] #hasMany
}
type Comment #model {
id: ID!
post: Post #belongsTo
content: String!
}
After run the command: amplify push
Amplify generate automatic code in the AWS Console (eg Service AppSync):
Example 1: Schema
enter image description here
Example 2: Mutation
enter image description here
My problem is that I don't know how to customize the resolvers because AWS AWS will overwrite my code.
Example: Now there is this code:
## [Start] Initialization default values. **
$util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {})))
#set( $createdAt = $util.time.nowISO8601() )
$util.qr($ctx.stash.defaultValues.put("id", $util.autoId()))
$util.qr($ctx.stash.defaultValues.put("createdAt", $createdAt))
$util.qr($ctx.stash.defaultValues.put("updatedAt", $createdAt))
$util.toJson({
"version": "2018-05-29",
"payload": {}
})
## [End] Initialization default values. **
How can I do that with AWS Amplify:
## [Start] Initialization default values. **
$util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {})))
#set( $createdAt = $util.time.nowISO8601() )
$util.qr($ctx.stash.defaultValues.put("id", "Hello"+$util.autoId()))
$util.qr($ctx.stash.defaultValues.put("createdAt", "2022-06-13T12:43:14.047Z"))
$util.qr($ctx.stash.defaultValues.put("updatedAt", "2022-06-13T12:43:14.047Z"))
$util.toJson({
"version": "2018-05-29",
"payload": {}
})
## [End] Initialization default values. **
How can I custom Resolver without overwriting issue?
Thanks you

Solution here: Override Amplify-generated resolvers
Link: https://docs.amplify.aws/cli/graphql/custom-business-logic/#override-amplify-generated-resolvers
You should create a .vtl file in the amplify/backend/api/<resource_name>/build/resolvers/ folder

Related

Why is my PaymentMethod ID not detected when I run my AWS stripe application via Docker?

I am learning web development and I am currently working on creating a lambda test application for stripe. The paymentMethod id from the front-end is not being detected by my lambda function when I run it locally by calling sam local start-api. I am doing my development on VS Code.
I followed the instructions on this page to create and run my application. My directory structure looks like this:
hello_world/app.py has my Lambda function.
The code for invoking the lambda end-point in script.jslooks like this:
var stripe = Stripe('pk_test_DIGITS');
var elements = stripe.elements();
form.addEventListener('submit', function(event) {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
stripe.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {
// Include any additional collected billing details.
name: 'Jenny Rosen',
},
}).then(stripePaymentMethodHandler);
});
function stripePaymentMethodHandler(result) {
if (result.error) {
// Show error in payment form
} else {
// Otherwise send paymentMethod.id to your server (see Step 4)
fetch('http://127.0.0.1:3000/payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
payment_method_id: result.paymentMethod.id,
})
}).then(function(result) {
// Handle server response (see Step 4)
result.json().then(function(json) {
handleServerResponse(json);
})
});
}
}
I ran the application on the browser by doing this:
When I click on Pay from my browser I can see the response in the logs on my dashboard:
The following code is for my lambda function app.py:
import json
import stripe
import requests
import logging
stripe.api_key= "sk_test_DIGITS"
def process_payment(event, context):
try:
print("START PRINTING")
print(event)
print("END PRINTING")
intent = stripe.PaymentIntent.create(
payment_method = 'event["body"]["payment_method_id"]',
amount = 1555,
currency = 'usd',
confirmation_method = 'automatic',
confirm = True,
payment_method_types=["card"]
)
return {
"statusCode": 200,
"body": json.dumps({
'clientSecret': intent['client_secret'],
# "location": ip.text.replace("\n", "")
}),
}
except Exception as e:
return {
"statusCode": 400,
"body": json.dumps({
"message": str(e),
# "location": ip.text.replace("\n", "")
}),
}
My template.yaml is as follows:
Globals:
Function:
Timeout: 30
Resources:
StripePaymentProcessor:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.process_payment
Runtime: python3.6
Events:
Payment:
Type: Api
Properties:
Path: /payment
Method: post
Outputs:
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Payment function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/payment/"
HelloWorldFunction:
Description: "Payment Lambda Function ARN"
Value: !GetAtt StripePaymentProcessor.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Payment function"
Value: !GetAtt StripePaymentProcessorRole.Arn
While keeping the browser window open, I ran the sam build command and it worked properly. After that I ran the sam local invoke command and it produced the following output:
I do not understand why event is empty. Should it not show the JSON data that got produced when I hit the pay button?
To do some trouble-shooting, I ran sam local start-api, invoked the POST method on Postman by pasting the JSON body from my Stripe logs:
What I did on Postman makes no sense to me and the snippet above raised another question for me. I do not understand why I see "message": "string indices must be integers" as a response on Postman.
EDIT:
After following wcw's suggestion I edited my fetch code to look like this:
I did not not see any written matter on the console by changing my code in this way.
I am keeping the browser open via the command prompt and I ran sam local start-api via the VS code console to keep http://127.0.0.1:3000/payment open. When I clicked on the pay button, I got the following response:
So the image above seems to indicate that the lambda function is not detecting the paymentmethod body.

searchkick reindex not working in staging env

In development environment Moment.reindex and search is OK, but in staging env is error:
2.3.1 :002 > Moment.reindex
Elasticsearch::Transport::Transport::Errors::BadRequest: [400] {"error":{"root_cause":[{"type":"parse_exception","reason":"Failed to parse content to map"}],"type":"parse_exception","reason":"Failed to parse content to map","caused_by":{"type":"json_parse_exception","reason":"Duplicate field 'moment'\n at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput#1e0d7046; line: 1, column: 2720]"}},"status":400}
staing env using same ES.
My Moment class:
class Moment
include Mongoid::Document
searchkick inheritance: true, callbacks: :async, merge_mappings: true, mappings: {
moment: {
properties: {
text: {
type: "text",
# analyzer: "ik_max_word",
fields: {
analyzed: {
type: "text",
analyzer: "ik_max_word"
}
}
}
}
}
}}
GET /_cat/indices?v
health status index
yellow open moments_development_20180223203756302
yellow open moments_staging
This was an issue with how mappings were merged. It's fixed in the latest version of Searchkick.

Symfony - Api-Platform framework: Get all items of a user

I'm a young developer and I recently discover Api-Platform to make a full rest api.
Currently, I'm following the doc, but I don't understand how to get all books of a person by example.
Here I am:
I have Book and Person entities auto generated, I just add a ManyToMany relation between them.
Then I have the following results:
GET api.platform.dev/app_dev.php/
{
#context: "/app_dev.php/contexts/Entrypoint",
#id: "/app_dev.php/",
#type: "Entrypoint",
person: "/app_dev.php/people",
book: "/app_dev.php/books"
}
GET api.platform.dev/app_dev.php/people/3
{
#context: "/app_dev.php/contexts/Person",
#id: "/app_dev.php/people/3",
#type: "http://schema.org/Person",
birthDate: null,
description: "test",
gender: "Femme",
name: "test",
url: null,
books: [
"/app_dev.php/books/1",
"/app_dev.php/books/4"
]
}
Here is my questions, How can I get in the second result an hypermedia to all books of the person, and What is the best option to get all books of a person ?
I have started with create my custom operation:
#services.yml
resource.person.item_operation.custom_get:
class: "Dunglas\ApiBundle\Api\Operation\Operation"
public: false
factory:
- "#api.operation_factory"
- "createItemOperation"
arguments:
- "#resource.person" # Resource
- ["GET"] # Methods
- "/people/{id}/books" # Path
- "AppBundle:Person:custom" # Controller
- "my_custom_route2" # Route name
- # Context (will be present in Hydra documentation)
"#type": "hydra:Operation"
"hydra:title": "A custom operation"
"returns": "xmls:string"
and
// PersonController.php
<?php
namespace AppBundle\Controller;
use Dunglas\ApiBundle\Controller\ResourceController;
use Symfony\Component\HttpFoundation\Request;
class PersonController extends ResourceController
{
public function customAction(Request $request, $id)
{
return parent::getAction($request, $id);
}
}
result on GET api.platform.dev/app_dev.php/people/3/books is the same of the basic api.platform.dev/app_dev.php/people/3, normal I call the parent.
But now what is the best way to have something like this:
# GET api.platform.dev/app_dev.php/people/3/books
{
#context: "/app_dev.php/contexts/Book",
#id: "/app_dev.php/people/3/books",
#type: "hydra:PagedCollection",
hydra:totalItems: 2,
hydra:itemsPerPage: 30,
hydra:firstPage: "/app_dev.php/people/3/books",
hydra:lastPage: "/app_dev.php/people/3/books",
hydra:member: [
{
#id: "/app_dev.php/books/1",
#type: "http://schema.org/Book",
illustrator: [ ],
isbn: null,
numberOfPages: 1230,
author: [ ],
datePublished: null,
description: "Desription",
genre: null,
name: "someone",
publisher: null
},
{
#id: "/app_dev.php/books/2",
#type: "http://schema.org/Book",
illustrator: [ ],
isbn: null,
numberOfPages: 1230,
author: [ ],
datePublished: null,
description: "Desription",
genre: null,
name: "someone",
publisher: null
}
]
}
And when I get api.platform.dev/app_dev.php/people/3 add this IRI /app_dev.php/people/3/books
Thanks you for the help you could give me.
Creating sub collections like this is doable but complex with the v1 of API Platform as it requires to create a lot of custom classes (it will be easier with the v2).
What I would suggest is to use the following structure:
GET /books?people=/people/3: retrieve all books owned bu the people 3
It can be done easily using the builtin API Platform search filter.
Then, if you want hypermedia support (btw do you really need it - I mean, is your client able to dereference such hypermedia links?), you need can create a custom Symfony normalizer decorating the Dunglas\ApiBundle\JsonLd\Serializer\ItemNormalizer (service api.json_ld.normalizer.item) provided by API Platform and adding a link to /books?people=/people/3 for the books property.
If you want to still want to follow the road you started, you need to use the Dunglas\ApiBundle\Hydra\Serializer\CollectionNormalizer to normalize your collection in the Hydra format. You can still decorate the ItemNormalizer to point to your custom collection URL.
I hope this help.

how to sync data from ydn-db web app to backend server?

With ydn-dn, i want to automatically synchronise data from my web app with my REST back end.
I read the documentation and searched in examples but i cannot make it work.
https://yathit.github.io/ydn-db/synchronization.html
http://dev.yathit.com/api/ydn/db/schema.html#sync
I tried to define a schema with sync configuration like that :
var schema = {
stores: [ {
name: 'contact',
keyPath: 'id',
Sync: {
format: 'rest',
transport: service,
Options: {
baseUri: '/'
}
}
}
]
};
and created a function for transport :
var service = function(args) {
console.log("contact synch");
};
but my service function is never called.
I certainly misunderstood how YDN-db work, but i didn't found any example.
To complete, here is a jsfiddle :
http://jsfiddle.net/asicfr/y7sL7b3j/
Please see the example http://yathit.github.io/ydndb-demo/entity-sync/app.html
Older example http://yathit.github.io/sprintly-service/playground.html from https://github.com/yathit/sprintly-service

How to access complex REST resources with ExtJS 5

I am using ExtJS 5 and I want to access complex REST resources as discussed in this similar thread using ExtJS 4.
The REST service that I am accessing exposes these resources:
GET /rest/clients - it returns a list of clients
GET /rest/users - it returns a list of all users
GET /rest/clients/{clientId}/users - it returns a list of users from the specified client.
I have these models:
Ext.define('App.model.Base', {
extend: 'Ext.data.Model',
schema: {
namespace: 'App.model'
}
});
Ext.define('App.model.Client', {
extend: 'App.model.Base',
fields: [{
name: 'name',
type: 'string'
}],
proxy: {
url: 'rest/clients',
type: 'rest'
}
});
Ext.define('App.model.User', {
extend: 'App.model.Base',
fields: [{
name: 'name',
type: 'string'
},{
name: 'clientId',
reference: 'Client'
}],
proxy: {
url: 'rest/users',
type: 'rest'
}
});
I did this:
var client = App.model.Client.load(2);
var users = client.users().load();
And it sent, respectively:
//GET rest/clients/2
//GET rest/users?filter:[{"property":"personId","value":"Person-1","exactMatch":true}]
Questions:
Is there any way that I can send my request to "GET rest/clients/2/users" without updating the user proxy url manually with its clientId?
How can I send above request without losing the original url defined in App.model.User, "rest/users"
I think this essentially the same as this question:
Accessing complex REST resources with Ext JS
I don't think much has changed since it was first asked.