Ember Data's REST Adapter accepts the JSON from the server in this format:
Taken from the documentation: http://guides.emberjs.com/v1.10.0/models/the-rest-adapter/
{
"post": {
"id": 1,
"title": "Node is not omakase",
"comments": [1, 2, 3]
},
"comments": [{
"id": 1,
"body": "But is it _lightweight_ omakase?"
},
{
"id": 2,
"body": "I for one welcome our new omakase overlords"
},
{
"id": 3,
"body": "Put me on the fast track to a delicious dinner"
}]
}
Is it possible to have this kind of JSON format back from strongloop?
Remote methods are not the best solution because they are per model, and thus not DRY.
You can make Ember-data compatible with Strongloop's loopback api by using the DS.RESTAdapter with DS.JSONSerializer like this:
// app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
host: 'http://loopback-api-host',
namespace: 'api',
defaultSerializer: 'JSONSerializer'
});
http://emberjs.com/api/data/classes/DS.JSONSerializer.html
"In Ember Data, the logic for communicating with a backend data store lives in the Adapter. Ember Data's Adapter has some built-in assumptions of how a REST API should look. If your backend conventions differ from these assumptions Ember Data makes it easy to change its functionality by swapping out or extending the default Adapter."
http://guides.emberjs.com/v2.0.0/models/customizing-adapters/
Similar question:
Making Loopback API Ember.js compatible
By default the out-of-box restful api endpoints would return something that looks more like:
{
"id": 1,
"title": "Node is not omakase",
"comments": [
{
"id": 1,
"body": "But is it _lightweight_ omakase?"
},
{
"id": 2,
"body": "I for one welcome our new omakase overlords"
},
{
"id": 3,
"body": "Put me on the fast track to a delicious dinner"
}
]
}
But you can use remote methods to do the same work and then massage the data into the way you want it to be returned. http://docs.strongloop.com/display/public/LB/Remote+methods
Related
I set up a basic model and controller connected to mysql database. Everything looks good and is working.
My Definition Model looks like this.
import { Entity, model, property } from '#loopback/repository';
#model({
settings: {
mysql: {
table: 'definition'
}
}
})
export class Definition extends Entity {
#property({
type: 'number',
id: true,
generated: true,
forceId: true,
required: false,
description: 'The unique identifier for a definition',
})
id: number;
#property({
type: 'string',
required: true,
})
name: string;
#property({
type: 'string',
required: true,
})
process_id: string;
constructor(data?: Partial<Definition>) {
super(data);
}
}
export interface DefinitionRelations {
// describe navigational properties here
}
export type DefinitionWithRelations = Definition & DefinitionRelations;
When I have it up and running and click on the explorer to test it out.
I click on "Try it out" for get /definitions and the only editable field that gets enabled is the filter field.
It is repopulated with a value like this...
{
"where": {},
"fields": {
"id": true,
"name": true,
"process_id": true
},
"offset": 0,
"limit": 0,
"skip": 0,
"order": [
"string"
]
}
I have to clear that to get it to work which is fine. When I run it with no filter it returns these results.
[
{
"id": 10,
"name": "Place Manual Payoff Order Process Config",
"process_id": "Process_PlaceManualPayoffOrderProcessConfig"
},
{
"id": 11,
"name": "test",
"process_id": "Test"
},
{
"id": 12,
"name": "test2",
"process_id": "test2"
}
]
I am trying to use the filter expression to only return ones with a specific process_id field. So I change the filter to look like this.
{
"where": {"process_id": "test2"}
}
And it still returns the same results.
[
{
"id": 10,
"name": "Place Manual Payoff Order Process Config",
"process_id": "Process_PlaceManualPayoffOrderProcessConfig"
},
{
"id": 11,
"name": "test",
"process_id": "Test"
},
{
"id": 12,
"name": "test2",
"process_id": "test2"
}
]
Do filters currently work in Loopback 4 or am I using them incorrectly?
EDIT: if I post the filters in the URL string they work. It seems as though the openapi ui isn't generating that part of the filter Into the URL string.
It seems as though the openapi ui isn't generating that part of the filter Into the URL string.
Yes, this a precise description.
OpenAPI Spec version 3.x does not specify how to serialize deeply-nested values to URL queries and swagger-js, the library powering swagger-ui (which powers LoopBack's REST API Explorer), silently ignores such values.
The issue has been reported and is being discussed here:
swagger-api/swagger-js#1385
OAI/OpenAPI-Specification#1706
I'm trying to create token with MPGS.
I'm following this guide:
https://sample-sub.domain.mastercard.com/api/documentation/integrationGuidelines/supportedFeatures/pickAdditionalFunctionality/tokenization/tokenization.html?locale=en_US#x_tokenConfiguration
In the section "Token Operations" > "Tokenize", it says:
You can use this operation to create or update a token by storing
payment details against the token. ...
I'm posting this to help people who are frustrating like me with MPGS. I faced series of issues, and pulled my hair off many times. So here's the issues I faced and how to solve them (I'm stuck with issue #4).
Issue #1: Invalid credentials.
Fix: Make sure you're hitting the correct URL.
https://example-subdomain.mastercard.com/..
https://some.other-example.mastercard.com/..
https://MILLION-OTHER-POSSIBILITIES.mastercard.com/..
Even the documentation guide link have these same sub-domains, so make sure you're hitting the correct URL, and make sure you're following the correct documentation link.
Issue #2: Invalid parameters, or server asking for parameters although you've provided them.
Fix: If using Postman, make sure you set the parameters in "Body" > "raw" as JSON, like so:
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Issue #3: Authorization required
Fix: If using Postman, click on "Authorization", set "Type" it to Basic Auth, for "Username" set it to merchant.YOUR_MERCHANT_ID, for "Password" set it to YOUR_API_PASSWORD
Issue #4 (stuck here): Value '9999999999999999' is invalid. Card token must not be supplied
Method: PUT
URL: https://test-my.sample.gateway.mastercard.com/api/rest/version/46/merchant/MY_MERCHANT_ID/token/9999999999999999
Authorization: set correctly in Authorization tab
Body > raw:
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Response:
{
"error": {
"cause": "INVALID_REQUEST",
"explanation": "Value '9999999999999999' is invalid. Card token must not be supplied",
"field": "tokenid",
"validationType": "INVALID"
},
"result": "ERROR"
}
Q: Not sure what to do to tokenize the transaction..?! I'm stuck with issue #4.
Ok, finally figured it out. MPGS has 2 ways to create/update tokens:
Tokenization where YOU provide the token (notice: PUT method)
Tokenization where MPGS generate the token for you (notice: POST method)
They're very similar.
I got it working with the 2nd option.
Note: This is POST method !!
Method: POST
URL: https://SUBDOMAIN_YOU_SHOULD_BE_USING.mastercard.com/api/rest/version/50/merchant/YOUR_MERCHANT_ID/token
In postman, set Authorization (as described in the question, in issue #3).
Sample data to send (in postman, this should be in Body > raw):
{
"sourceOfFunds": {
"provided": {
"card": {
"expiry": {
"month": "05",
"year": "21"
},
"number": "5123456789012346"
}
},
"type": "CARD"
}
}
Sample response:
{
"repositoryId": "1000000000002",
"response": {
"gatewayCode": "BASIC_VERIFICATION_SUCCESSFUL"
},
"result": "SUCCESS",
"sourceOfFunds": {
"provided": {
"card": {
"brand": "MASTERCARD",
"expiry": "0521",
"fundingMethod": "CREDIT",
"issuer": "BANCO DEL PICHINCHA, C.A.",
"number": "512345xxxxxx2346",
"scheme": "MASTERCARD"
}
},
"type": "CARD"
},
"status": "VALID",
"token": "9717501974559694",
"usage": {
"lastUpdated": "2019-02-25T09:36:54.928Z",
"lastUpdatedBy": "1015",
"lastUsed": "2019-02-25T09:36:54.928Z"
},
"verificationStrategy": "BASIC"
}
I have two models in Ember:
Collection
export default DS.Model.extend({
name: DS.attr(),
description: DS.attr(),
items: DS.hasMany('collection-item')
});
Collection Item
export default DS.Model.extend({
date: DS.attr(),
volume: DS.attr(),
sequenceNumber: DS.attr()
});
I want to save the collection items inside the 'items' attribute of the collection, like MongoDB:
[{
"name": "First Collection",
"description": "This is my first collection",
"items": [
{
"date": "2017-07-26",
"volume": "1",
"sequenceNumber": "1"
},
{
"date": "2017-07-27",
"volume": "1",
"sequenceNumber": "2"
}
]
},
{
"name": "Second Collection",
"description": "This is my second collection",
"items": [
{
"date": "2017-07-26",
"volume": "1",
"sequenceNumber": "1"
},
{
"date": "2017-07-27",
"volume": "1",
"sequenceNumber": "2"
}
]
}]
I have read something about serializers, but I don't get the point ;) Can someone give me a hint?
BTW, I'm using Firebase (emberfire) for now, but I'm going to build my own API in future.
What you're describing is known as an embedded record in Ember. On the serializers page, beneath the discussion of the JSONAPISerializer is a discussion of the embedded record mixin: https://guides.emberjs.com/v2.14.0/models/customizing-serializers/
You can use a RESTSerializer with an embedded mixin to achieve what you're after.
That said, unless your backend needs are fairly simple, I'd suggest beginning to build a backend (and using JSON-API for it) before you get too far. JSON-API is a spec based off of pain points the entire Ember community has felt over the years. If you build a simpler backend right now, you may find yourself hitting headaches in the future that JSON-API is specifically designed to address.
Good luck!
If you are using the defaults from Ember Data, you need to have a JSON API compatible backend service where to retrieve/send data from. You can take a look at the projects implementing JSON API standards if you don't have a backend yet.
After you have a working API, the rest is fairly straightforward and well documented.
Possibly I'm misunderstanding how Ember wants to lazy load hasMany sides of relationships but I'll specify what I want and someone can tell me if it is possible and how to configure things.
I'm using the RESTAdapter and I have a parent object with a 1-to-many relationship with several other objects. When I view the parent, I have links for the children objects that I want to show as child outlets.
Examples might be:
// brand.js
export default Model.extend({
name: attr('string'),
description: attr('string'),
dateCreated: attr('date'),
lastUpdated: attr('date'),
regions: hasMany('region', {async: true})
});
// region.js
export default Model.extend({
name: attr('string'),
dateCreated: attr('date'),
lastUpdated: attr('date'),
brand: belongsTo()
});
When I access /api/brands/1 I'm returning the following JSON:
{
"brand": {
"id": 1,
"dateCreated": 1466456255539,
"lastUpdated": 1466456255936,
"name": "Some Brand",
"description": "Voluptates odio nemo corrupti",
}
}
I have my route defined like so:
this.route('brand', {path: '/brands/:brand_id'}, function() {
this.route('regions');
});
So, in the brand detail screen, I have an {{outlet}} and when I click on the link for regions, I need to fetch the regions for that brand, and the URL would be /api/brands/1/regions.
Everything works if I return all the data in one big result, and my regions router looks like this:
export default Ember.Route.extend({
model() {
return this.modelFor('brand').get('regions');
}
});
But I don't know what to do so that regions gets lazily fetched correctly from my API. Or if it is even possible. I read up on side loading and currently, my API won't return ID's only for children.
With your example, ember.js does not know, what regions to load. Your JSON has to be either (non-embedded):
{
"brand": {
"id": 1,
"dateCreated": 1466456255539,
"lastUpdated": 1466456255936,
"name": "Some Brand",
"description": "Voluptates odio nemo corrupti",
"regions": ["5", "9"]
}
}
Which then loads regions with the id 5 and 9. Or you could embed them directly:
{
"brand": {
"id": 1,
"dateCreated": 1466456255539,
"lastUpdated": 1466456255936,
"name": "Some Brand",
"description": "Voluptates odio nemo corrupti",
"regions": [{
"id": "5",
"name": "Hanover",
"dateCreated": "2016-09-25 18:39:18",
"lastUpdated": "2016-09-25 18:39:18",
},{
"id": "9",
"name": "Cologne",
"dateCreated": "2016-01-19 11:59:18",
"lastUpdated": "2016-02-22 12:09:58",
}]
}
}
See here for the latter.
I'm trying to determine how best to define my models. I'm trying to represent an asset. Ex: car, tv, house, etc.
Here's the payload coming from my server:
{
"asset": {
"id": "1b0b77a2-28d7-488e-9a6f-8a202c297593",
"created_at": "2015-03-19T09:16:43+0500",
"updated_at": "2015-03-19T09:16:43+0500",
"name": "Flat Screen Tv",
"properties": [
{
"name": "brand",
"value": "Sony",
"public": false,
"family": false,
"friends": false
},
{
"name": "price",
"value": 1000,
"public": false,
"family": false,
"friends": false
}
]
}
}
It needs to get POSTed back in the same format. How can I define this model with ember data? The properties are hanging me up. I thought I could just define a transformer but then noticed that changing values in the transformed data doesn't update the asset's "dirty" flag. I need that dirty flag to be updated when the properties get changed. Any ideas?
// app/transforms/array.js
import Ember from 'ember';
import DS from 'ember-data';
export default DS.Transform.extend({
serialize: function(value) {
return value.toArray();
},
deserialize: function(value) {
return Ember.A(value);
}
});
Here's my asset model definition.
import DS from 'ember-data';
// app/models/asset.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date'),
properties: DS.attr('array')
});
Your properties are going to have to be a separate model, and related to your asset models with hasMany. If that doesn't work for you, you might have to rethink how you are storing your properties.