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
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.
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.
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.
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
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.