Getting image URL from Contentful entry id - contentful

I need to get an image URL from Contentful entry id.
I am getting such an JSON from Contentful query
{
"sys":{
"space":{
"sys":{
"type":"Link",
"linkType":"Space",
"id":"8v1e7eaw70p2"
}
},
"id":"1JfEwVlD9WmYikE8kS8iCA",
"type":"Entry",
"createdAt":"2018-02-28T18:50:08.758Z",
"updatedAt":"2018-02-28T18:50:08.758Z",
"revision":1,
"contentType":{
"sys":{
"type":"Link",
"linkType":"ContentType",
"id":"image"
}
},
"locale":"en-US"
},
"fields":{
"name":"heat",
"image":{
"sys":{
"type":"Link",
"linkType":"Asset",
"id":"6Inruq2U0M2kOYsSAu8Ywk"
}
}
}
}
I am using JS driver they provide:
client.getEntry()
so how to go thru that link: 6Inruq2U0M2kOYsSAu8Ywk ?

Unfortunately, the js SDK will not be able to resolve links when using the single entry endpoint i.e client.getEntry() because there won't be enough data.
When thing I always recommend to work around this is to use the collection endpoint with a query the desired id as a query param. This way you will always get the desired entry with all it's linked data.
Your code should look something like this
client.getEntries({'sys.id': '6Inruq2U0M2kOYsSAu8Ywk'})
.then(response => console.log(response.items[0].fields.image.fields.file.url))
I hope that helps.
Best,
Khaled

Use client.getEntries({'sys.id': '1JfEwVlD9WmYikE8kS8iCA'})
To get the entry fields and the asset fields.
You can also patch the assets to the fields by running this after fetching the data:
/* Patch all the assets to the fields */
const patchAssets = (fields, assets) => {
Object.keys(fields).forEach(function (key) {
let obj = fields[key];
if (obj.sys && obj.sys.linkType === 'Asset') {
const assetId = obj.sys.id;
const matchAsset = assets.find(asset => {
return asset.id === assetId;
});
obj.file = matchAsset;
}
});
return fields;
};

Another way to get image url is to use getAsset('<asset_id>'). So first, using the getEntry() method, you need to get the entry data, then extract the id from the field: fields.image.sys.id, and pass it to the getAsset method.

Related

contentful getEntries published data only

Is there a way to query the results to show only data that has been published and is not in draft state? I looked in the documentation and didn't quite find it.
This is what I currently have:
export const getAllPages = async (context?) => {
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});
const pages = await client.getEntries({
content_type: "page",
include: 10,
"fields.slug[in]": `/${context.join().replace(",", "/")}`,
});
return pages?.items?.map((item) => {
const fields = item.fields;
return {
title: fields["title"],
};
});
};
You can detect that the entries you get are in Published state:
function isPublished(entity) {
return !!entity.sys.publishedVersion &&
entity.sys.version == entity.sys.publishedVersion + 1
}
In your case, I would look for both Published and Changed:
function isPublishedChanged(entity) {
return !!entity.sys.publishedVersion &&
entity.sys.version >= entity.sys.publishedVersion + 1
}
Check the documentation:
https://www.contentful.com/developers/docs/tutorials/general/determine-entry-asset-state/
To get only the published data you will need to use the Content Delivery API token. If you use the Content Preview API Token, you will receive both the published and draft entries.
You can read more about it here: https://www.contentful.com/developers/docs/references/content-delivery-api/
If using the Content Delivery API you need to filter on the sys.revision attribute for each item. A published item should have its revision attribute set to greater than 0.
const publishedItems = data.items.filter(item => item.sys.revision > 0)

Trying to get id parameter with nodejs and acces it in angular

I am trying to access a detail page that i have for a list of items in my html(ionic). So when I click on 1 item I need to go on a detail page with information about that specific item. I am using mongo database for the items , the model of the items are : name and ingredients.
I am stuck here and don't know what to do , please help if you have a bit of time , thank you.
My code :
<ion-list *ngFor="let recipe of recipes ; let i = index">
<ion-item>
<ion-label>{{recipe.name}}</ion-label>
</ion-item>
</ion-list>
Request for the database trying to get the id to access the item (I get the
public findByName(id: string) {
return this.http.get<any>(
"http://localhost:9020/:id" + id
);
}
This is what I tried in typescript
this.route.paramMap.subscribe((paramMap) => {
if (!paramMap.has("id")) {
this.navCtrl.navigateBack("/home");
return;
}
this._recipeDetail = this.nutService
.findByName(paramMap.get("id"))
.subscribe((id) => {
this.id = id;
});
});
Also in route module :
{
path: "name/:id",
loadChildren: () =>
import("./r-d/r-d.module").then(
(m) => m.RDPageModule
),
},
But its not working , maybe I don't have the right approach? Can someone please guide me a bit ?
Thank you for your time
this._recipeDetail = this.nutService
.findByName(paramMap.get("id"))
.subscribe((id) => {
this.id = id;
});
You should be expecting your api to return you the recipeDetail.. you are not storing it properly.
this.nutService.findByName(paramMap.get("id"))
.toPromise().then((data) => {
this.recipeDetail = data;
});
And then, you can display your recipeDetail inside your template. I have also changed .subscribe() to .toPromise().then(). This is a better approach to avoid memory leaks in your app.

requests module returns JSON with items unordered

When I'm using node's requests module this way:
router.get('http://[some_api_url]')
res.send()
I get different JSON ordered in contrary to viewing the JSON via browser.
For example, via res.send() I get:
[{"key1":"value1","key2":"value2"},{"key1":"value1","key2":"value2"}]
Whereas via browser I see it as supposed to be:
[{"key2":"value2","key1":"value1"},{"key2":"value2","key1":"value1"}],
The function is this:
getAllEvnets:async(req, res)=> {
let event = []
try{
var listEvent = await events.findAll()
for (let i = 0; i < listEvent.length; i++) {
event.push({
id: listEvent[i].id_event,
start: listEvent[i].debut,
end : listEvent[i].fin,
title: listEvent[i].title,
color: {red: {
primary: '#ad2121',
secondary: '#FAE3E3'}
},
actions: ''
})
}
res.json(event)
}
catch(err){
res.send(err.message)
}
}
ECMAscript says...
The mechanics and order of enumerating the properties ... is not
specified.
So there is no guarantee that it will be ordered. Anyway usually it dont need it to be ordered you acces it with an dot notation like key1.value1. No matter if its the first property in the object or the last one, it doenst matter.

Multiple urls in a get request with axios.all, how do I match response.data to its appropriate url object?

I am building a tool to use for work. Basically I upload a csv to extract details which will act as parameters in an axios get request.
I am using multiple urls in axios.all, and my problem is I cannot match up the reponse data to each object of that specific url. The details are below with code snippets. I hope I've made it clear enough below, but this has to do with mass requesting many urls at once, and receiving response data. The problem lies in matching up that response data to its correct url from which it was called.
Here we go...to start, I am mapping an array of vehicle data I am uploading from an external csv file. 'resultsArray' is my array and it holds the year, make, model, trim, price, a url to locate the original posting, and location of the vehicle.
let vehicle_specs = resultsArray.map(function(d, index) {
let values = {
year: d['Title_name'].split(' ')[0], // Iterate with bracket notation
make: d['Title_name'].split(' ')[1],
model: d['Title_name'].split(' ')[2],
trim: d['Title_name'].split(' ')[3],
price: d['Title_Price'],
cl_url: d['Title_Price_url'],
cl_location: d['Title_Location'],
}
return values;
});
I use the new keyword to create an object of the vehicle.
let Vehicle = function(year, make, model, trim, price, url, cl_url, cl_location) {
this.year = year;
this.make = make;
this.model = model;
this.trim = trim;
this.price = price;
this.url = url;
this.cl_url = cl_url;
this.cl_location = cl_location;
}
I then build the object with a new instance of Vehicle and return each vehicle as I need it to be.
let vehicle_data = vehicle_specs.map(function(s) {
let url = `http://api.marketcheck.com/v2/stats/car?api_key={}&ymm=${s.year}|${s.make}|${s.model}`;
let new_vehicle = new Vehicle(`${s.year}`, `${s.make}`, `${s.model}`, `${s.trim}`, `${s.price}`, `${url}`, `${s.cl_url}`, `${s.cl_location}`);
return new_vehicle;
});
I extract the URL's in the following code snippet and use axios.all to request data from each one.
let urls = vehicle_data.map(function(m) {
return m.url;
})
let options = {
'method': 'GET',
'headers': {
'Host': 'marketcheck-prod.apigee.net'
}
};
axios.all(urls.map(url => {
request(url, options, function (error, response, body) {
if(error) {
console.log(error);
} else {
console.log(response);
}
});
}))
My Problem:
I am using a 3rd Party API (Marcketcheck) - Holds data on vehicles.
The response data comes back (See below as an example. This is data for just 1 url)
{"price_stats":{"geometric_mean":3413,"min":899,"median":3595,"population_standard_deviation":1323,"variance":1750285,"ax":7995,"mean":3655,"trimmed_mean":3572,"standard_deviation":1323,"iqr":1800},"miles_stats":{"geometric_mean":97901,"min":2,"median":125000,"population_standard_deviation":51713,"variance":2147483647,"max":230456,"mean":125182,"trimmed_mean":125879,"standard_deviation":51713,"iqr":74734},"dom_stats":{"geometric_mean":100,"min":1,"median":100,"population_standard_deviation":399,"variance":159152,"max":2513,"mean":247,"trimmed_mean":162,"standard_deviation":399,"iqr":217},"count":101}
I cannot figure out how to match up each response data to the vehicle object of that specific url.
For example, if I request 3 urls from the vehicle object. Let's name them:
Url-1
Url-2
Url-3
I get my response data back as objects:
OBJ-1
OBJ-2
OBJ-3
I have no way as far as I know with my level of knowledge, how to assign each object back to it's specific URL and THEN, match up that OBJ data with it's specific vehicle.
I haven been beating my head against a wall for about 4 days, I cannot figure this out.
Any suggestions are welcome and I really appreciate anybody looking at this post to help out.
Check this out
let requests = urls.map((url) => {
return axios.get(url, {
headers: {
'Host': 'marketcheck-prod.apigee.net'
}
});
});
Promise.all(requests).then((responces) => {
console.log(responces);
}).catch((err) => {
console.log(err)
});

Passing path parameters in axios

I am using Axios with NodeJs and trying to pass path parameters in axios.get() method. For example, if URL is url = '/fetch/{date}', I want to replace {date} with the actual date while calling axios.get(url).
I went through the source code on Github and StackOverflow, but couldn't find any method.
Is it possible to keep URLs with parameters as a placeholder and replace them while actually calling the get method of Axios?
Axios doesn't have this feature and it looks like the team don't want to add it.
With credit to previous responders for inspiration, to me this seems like the solution closest to what you (and me) are looking for:
1 - Where you want to store all your URLs and their parameters, define them as functions which use a template string to return the composed URL:
export var fetchDateUrl = (date) => `/fetch/${date}`;
If you need any type-specific formatting of the value being concatenated into the URL, this function is a good place to do it.
2 - Where you want to make the request, call the function with the correct parameters:
import { fetchDateUrl } from 'my-urls';
axios.get(fetchDateUrl(someDateVariable))...;
Another variation, if you really like the idea of naming the parameters at the call site, you can define the URL function to destructure an object like this:
var fetchDateUrl = ({date}) => `/fetch/${date}`;
which you'd then use like this:
axios.get(fetchDateUrl({date: someDateVariable}));
Use template strings
url = `/fetch/${date}`
Or just tag it on
url = '/fetch/'+ date
I think using axios interceptors is better to do this :
//create your instance
const instanceAxios = axios.create({
baseUrl: 'http://localhost:3001'
]);
instanceAxios.interceptors.request.use(config => {
if (!config.url) {
return config;
}
const currentUrl = new URL(config.url, config.baseURL);
// parse pathName to implement variables
Object.entries(config.urlParams || {}).forEach(([
k,
v,
]) => {
currentUrl.pathname = currentUrl.pathname.replace(`:${k}`, encodeURIComponent(v));
});
const authPart = currentUrl.username && currentUrl.password ? `${currentUrl.username}:${currentUrl.password}` : '';
return {
...config,
baseURL: `${currentUrl.protocol}//${authPart}${currentUrl.host}`,
url: currentUrl.pathname,
};
});
// use like :
instanceAxios.get('/issues/:uuid', {
urlParams : {
uuid: '123456789'
}
})
For typescript users, you will need to add this, in one of your .d.ts
declare module 'axios' {
interface AxiosRequestConfig {
urlParams?: Record<string, string>;
}
}
( this is a POC, not really tested, doesn't hesitate if you see something wrong )
You can use template strings ie:
let sellerId = 317737
function getSellerAnalyticsTotals() {
return axios.get(`http://localhost:8000/api/v1/seller/${sellerId}/analytics`);
}
Given some API /fetch/${date} you likely want to wrap your axios call in a function.
const fetchData = (date) => axios.get(`/fetch/${date}`);
fetchData(dateObject.toFormat('yyyy-mm-dd'))
.then(result => { ... });
This requires the calling code to format date correctly however. You can avoid this by using a DateTime library that handles date string parsing and do the format enforcement in the function.
const fetchData = (date) => axios.get(`/fetch/${date.toFormat('yyyy-mm-dd')}`);
fetchData(dateObject)
.then(result => { ... });
you can do like this:
getProduct = (id) => axios.get(`product/${id}`);
I always do it like this:
const res = await axios.get('https://localhost:3000/get', { params: { myParam: 123 } });
I find this to be much clearer than template strings.
More explanation here

Resources