I'm trying to learn about API's and am creating a simple response when a user hit's an endpoint on my basic express app.
I'm not sure what constitutes a correct API response though, does it need to be an object?
The data I was given is an array of arrays and I export it from a file and return it in the express app as an object using response.json(), it displays ok but I'm not sure if I'm following the right approach for how I'm handling it and displaying it.
I would like to understand how should API data be returned, I had the feeling that it should always be an object but what I'm returning here is an array of arrays, some explanation to understand this better would be helpful please.
Here is my data file:
export const data = [
[
'a9e9c933-eda2-4f45-92c0-33d6c1b495d8',
{
title: 'The Testaments',
price: { currencyCode: 'GBP', amount: '10.00' },
},
],
[
'c1e435ad-f32b-4b6d-a3d4-bb6897eaa9ce',
{
title: 'Half a World Away',
price: { currencyCode: 'GBP', amount: '9.35' },
},
],
[
'48d17256-b109-4129-9274-0bff8b2db2d2',
{ title: 'Echo Burning', price: { currencyCode: 'GBP', amount: '29.84' } },
],
[
'df2555ad-7dc2-4b1f-b422-766184b5c925',
{
title: ' The Institute',
price: { currencyCode: 'GBP', amount: '10.99' },
},
],
];
Here is a snippet from my express app file which imports the data object for this endpoint:
app.get('/books', (request, response) => {
response.json({ books: data });
});
Looks okay, one thing I would do is ensure the root of the object you return always has the same name between api calls, so here your root object name is "books":
app.get('/books', (request, response) => {
response.json({ books: data });
});
I would personally change this to something like:
app.get('/books', (request, response) => {
response.json({ data: data });
});
Now that may seem confusing, but what that means is when your api is queried, the actual resources the api is returning is always in an object called data, it just builds a common pattern for where people should be expecting to see the api response resources in your JSON response.
So if you had another endpoint for authors for example, people will know the authors response will be under an object called data:
app.get('/authors', (request, response) => {
response.json({ data: authors });
});
Related
A similar question has been asked before, but didn't answer the question directly. With Stripe's create subscription call:
stripe.subscriptions.create({
customer: "cus_FrggXOPDIf2ldT",
items: [
{
plan: "plan_FrbdKwJE959Ivb",
},
]
}, function(err, subscription) {
// asynchronously called
}
);
There is a subscription object that is returned. Is this object returned in the callback function that is returned asynchronously? I've tried the following without success:
stripe.subscriptions.create({
customer: "cus_FrggXOPDIf2ldT",
items: [
{
plan: "plan_FrbdKwJE959Ivb",
},
]
}, function(err, subscription) {
console.log(subscription.id);
}
);
How is the id returned, and how to grab it?
Ah, I should have known the create subscription call returned a promise. So in that case:
stripe.subscriptions.create(
{
customer: id,
items: [
{
plan: 'plan_FrbdKwJE959Aws',
},
],
},
).then(subscription => console.log(subscription.id));
I'm writing an analytics application that collects events and associates it with visitors.
My Visitor mongoose model as follows:
var visitorSchema = new Schema({
created_at: { type: Date, default: Date.now },
identifier: Number,
client_id: Number,
account_id: Number,
funnels: [String],
goals: [Goal],
events: [Event]
});
The api accept a mixed of visitor info and the event
{
"identifier": 11999762224,
"client_id": 1,
"account_id": 1,
"event": {
"context": "Home",
"action": "Click red button",
"value": ""
}
}
When restify receives a request it checks if the visitor exists, and if it exists the ap just push the event as follows:
server.post('/event', function (req, res, next) {
Visitor.findOne({
identifier: req.params.identifier,
client_id: req.params.client_id,
account_id: req.params.client_id
}, function(err, visitor) {
if(err) {
console.log(err);
res.send(500, visitor);
}
if(visitor) {
visitor.events.push(req.params.event);
visitor.save();
} else {
visitor = new Visitor({
identifier: req.params.cpf,
client_id: req.params.client_id,
account_id: req.params.client_id,
funnels: req.params.funnels,
events: req.params.event
});
visitor.save();
}
res.send(200, visitor);
});
});
By using this method, and I trigger several concurrent requests I get duplicated visitors instead of one visitor with multiple events.
How can I solve this issue? Whats the best approach?
Add a unique index on identifier in mongoose model. This way the second request will break with unique index violation. Just make sure you handle that error.
If you are using single page framework on the client side (angular, backbone etc) make sure you disable the button when you make an api call, and enable it on server response.
I'm trying to make a call to addFixedPriceItem in NodeJS. I'm using the NodeJS eBay API. My code is the following:
var ebay = require('ebay-api');
ebay.ebayApiPostXmlRequest({
serviceName: 'Trading',
opType: 'AddFixedPriceItem',
devName: myDevId,
cert: myCertId,
appName: myAppId,
sandbox: true,
title: title,
params: {
'authToken': myClientAuthToken,
version: EBAY_API_VERSION,
Item: {
Country: 'EBAY-US',
Currency: 'USD',
Description: description,
ListingType: 'FixedPriceItem',
PictureDetails: picturesArray,
Quantity: '5',
StartPrice: price
},
}
}, function (error, results) {
if (error) {
console.dir(error);
process.exit(1);
}
console.dir(results);
});
Ultimately, I cannot seem to get it to call. It's not a verification issue or anything, console is stating that No Item.Country exists, and No Item.Currency exists, although I have specifically placed these in my parameters. Any clue why this would occur?
If not, how could I make a call to this in nodeJS without this API? I appreciate any help! :)
Your country code is wrong. It should be 'US' or one of the other CountryCodeType's.
I am currently using StrongLoop as my API backend server and Mongodb as data storage engine.
Let's say there is a collection called article. It has two fields title, and content. And there are two frontend pages to display a list of articles and view a single article.
Obviously the data list page only need title field and the view page need both. Currently the GET method of StrongLoop API return all fields including content. It cost extra traffic. Is there any way that can just return specific field?
Mongodb support projection in find() method for this. How can I do the same thing by StrongLoop?
Have you taken a look at the filters offered. http://docs.strongloop.com/display/LB/Querying+models
Query for NodeAPI:
server.models.Student.findOne({where: {RFID: id},fields: {id: true,schoolId: true,classId: true}}, function (err, data) {
if (err)
callback(err);
else {
callback();
}
})
Query for RestAPI :
$http.get('http://localhost:3000/api/services?filter[fields][id]=true&filter[fields][make]=true&filter[fields][model]=true')
.then(function (response) {
}, function (error) {
});
You can use fields projections,
Sample Record:
{ name: 'Something', title: 'mr', description: 'some desc', patient: { name: 'Asvf', age: 20, address: { street: 1 }}}
First Level Projection:
model.find({ fields: { name: 1, description: 1, title: 0 } })
and I think Strong loop is not yet supporting for second-level object filter, does anyone know how to filter second-level object properties or is yet to implement?.
Second Level Projection: (Need help here)
Ex: 2
model.find({ fields: { name: 1, 'patient.name': 1, 'patient.age': 1, 'patient.address': 0 } })
// Which results { name } only
Let's suppose I have two simple fixture files, one for the user(1) and one for the messages(2).
The Backbone Model for the messages is the following (3).
If I load the "Message Fixture", I would like to have also the related info regarding the user as specified in Message Model.
What is the proper way to active this goal in a spec view (4) by using jasmine test suite?
Please see the comments in (4) for more details.
(1)
// User Fixture
beforeEach(function () {
this.fixtures = _.extend(this.fixtures || {}, {
Users: {
valid: {
status: 'OK',
version: '1.0',
response: {
users: [
{
id: 1,
name: 'olivier'
},
{
id: 2,
name: 'pierre',
},
{
id: 3,
name: 'george'
}
]
}
}
}
});
});
(2)
// Message Fixture
beforeEach(function () {
this.fixtures = _.extend(this.fixtures || {}, {
Messages: {
valid: {
status: 'OK',
version: '1.0',
response: {
messages: [
{
sender_id: 1,
recipient_id: 2,
id: 1,
message: "Est inventore aliquam ipsa"
},
{
sender_id: 3,
recipient_id: 2,
id: 2,
message: "Et omnis quo perspiciatis qui"
}
]
}
}
}
});
});
(3)
// Message model
MessageModel = Backbone.RelationalModel.extend({
relations: [
{
type: Backbone.HasOne,
key: 'recipient_user',
keySource: 'recipient_id',
keyDestination: 'recipient_user',
relatedModel: UserModel
},
{
type: Backbone.HasOne,
key: 'sender_user',
keySource: 'sender_id',
keyDestination: 'sender_user',
relatedModel: UserModel
}
]
});
(4)
// Spec View
describe('MyView Spec', function () {
describe('when fetching model from server', function () {
beforeEach(function () {
this.fixture = this.fixtures.Messages.valid;
this.fixtureResponse = this.fixture.response.messages[0];
this.server = sinon.fakeServer.create();
this.server.respondWith(
'GET',
// some url
JSON.stringify(this.fixtureResponse)
);
});
it('should the recipient_user be defined', function () {
this.model.fetch();
this.server.respond();
// this.fixtureResponse.recipient_user is not defined
// as expected by the relation defined in (3)
expect(this.fixtureResponse.recipient_user).toBeDefined();
});
});
});
});
Take a look at this series of tutorials http://tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html
This is the specific part about Model testing.
Don't know if will solve your problem, but may contain precious info.
this.fixtureResponse is the source data for the model, but when the model is actually created it makes a copy of that data to an internal property. So, when Backbone Relational resolves the relation, it shouldn't change the source data object.
Did you tried with expect(this.model.get('recipient_user')).toBeDefined()?
Backbone-Relational provides the ability to either create a related model from nested entities within JSON retrieved via the model's fetch or to lazily load related models using fetchRelated.
You're providing Backbone-Relational with the message model data but no way to retrieve the user model data. You could add another response returning the appropriate related user data and call fetchRelated on the message model.
Alternatively inline the user data into the message response and the user model will be created automatically and added as a relation on the message model.