fetch all github repo by Github api v3 and javascript - github

I discovered that by default the API responds with 30 repos.
May I know how should I use for loop to retrieve all repos?
const axios = require('axios');
const repoUrl = `https://api.github.com/users/USERNAME/repos`;
access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
// console.log
const config = {
headers: {Authorization: `Bearer ${access_token}`} # only 30
};
axios.get(repoUrl, null, config).then((responses) => {
const repos = responses.data.map(({name, language, html_url, created_at, description}) => {
return {name, language, html_url, created_at, description};
})
console.log("number of repo ", repos.length);
}).catch(error => {
console.log(`getrepos error: ${error}`)
});
by https://docs.github.com/en/rest/reference/repos#list-repositories-for-the-authenticated-user--parameters , there is a page parameter
but how should I write the for loop? should I loop the page with 1,2,3,4.... until server give me some error?

You can make a GraphQL query with Axios, as in this example, or in this article:
axios({
url: 'https://graphql.com/graphql',
method: 'post',
data: {
query: `
query {
viewer {
repositories(isFork: false) {
totalCount
}
}
}`
}
}).then((result) => {
console.log(result.data)
});
Once you have the total number of repositories, you start looping (only the exact amount of loop), as described here:
//Start fetching every page of repos.
const fetchPromises = [], pageCount = Math.ceil(repoCount /
MAX_PER_PAGE);
for (let pageI = 1; pageI <= pageCount; ++pageI) {
const fetchPagePromise = fetch(baseUrl + '&page=' + pageI);
fetchPromises.push(fetchPagePromise);
}

Related

Redeliver existing form submission to new webhook

I have set up a webhook between salesforce and Typeform and it's working fine. But Typeform has already filled form submissions. Now I want to deliver these responses to a new webhook is there a way to resync existing form submissions?
I dont think this is possible out of the box. You will need to fetch your responses via Typeform Responses API and feed them to your script or webhook.
It looks like the webhook payload is quite similar to the response returned by the API. You can write a script like this to feed all your existing responses from your typeform to a new webhook:
import fetch from 'node-fetch'
import crypto from 'crypto'
import { createClient } from '#typeform/api-client'
const token = process.env.TF_TOKEN // https://developer.typeform.com/get-started/personal-access-token/
const webhookSecret = process.env.SECRET
const uid = process.env.FORM_ID
const typeformAPI = createClient({ token })
const sleep = async (ms) => new Promise(res => setTimeout(res, ms))
// based on https://glitch.com/edit/#!/tf-webhook-receiver
const calculateSignature = (payload) => {
const hash = crypto
.createHmac('sha256', webhookSecret)
.update(payload)
.digest('base64')
return `sha256=${hash}`
}
const feedResponses = (before) => {
typeformAPI.responses.list({ uid, before }).then(async ({ items }) => {
if (items.length > 0) {
// process each response
for (let i=0; i<items.length; i+=1) {
const item = items[i]
const body = JSON.stringify({
"event_id": Date.now(),
"event_type": "form_response",
"form_response": item
})
const response = await fetch('/your-endpoint', {
method: 'POST',
headers: {
'Typeform-Signature': calculateSignature(body)
},
body,
})
const webhookResponse = await response.text()
console.log(webhookResponse)
await sleep(250) // rate-limit the requests
}
// continue with next page of responses
const { token } = items.at(-1)
feedResponses(token)
}
})
}
feedResponses()

strapi + nuxt search by slug

I'm modifing my strapi and nuxt site to find my post by slug instead of id
https://forum.strapi.io/t/strapi-v4-search-by-slug-instead-id/13469/21
this is working, but when i do my axios request in _slug.vue the url is correct but it doesn't save the info in my response variable, in my browser console says can't read data from undefined, checked the url is correct and in my strapi console i have everything ok.
async asyncData({ route, i18n, title, description }) {
try {
const locale = i18n.locale;
const qs = require("qs");
const query = qs.stringify(
{
populate: "*",
publicationState: "live",
locale: [locale],
},
{
encodeValuesOnly: true,
}
);
const response = await axios.get(
`http://localhost:1337/api/posts/${route.params.slug}/?&` +
query
);
console-log(response)
let post = response.data;
if (locale != post.data.attributes.locale) {
post.data.attributes.localizations.data.forEach((element) => {
if (element.attributes.locale === locale) {
title = element.attributes.title;
description = element.attributes.description;
}
});
} else {
title = post.data.attributes.title;
description = post.data.attributes.description;
}
return { post, title, description };
} catch (error) {
this.error = error.response.data.error.details.errors;
}
},
Any ideas? thanks

Nuxtjs meta not working in vercel deployment. but working in local dev server

when calling API in asyncData with static parameter meta working in both local and vercel server. but if parameter make dynamic live server meta not working
async asyncData(context) {
let pageinfo = ''
try {
console.log(context.query.id)
const url_key = 'cocomama-coconut-water-250ml'
const custId = ''
const guestId = ''
const API_HEADER = Config.ADMIN_API_HEADER.headers
API_HEADER.vendorUrlKey = 'centrealbazaarindialtdkaloor'
pageinfo = await fetch(
`${
Config.BASE_URL
}ProductDetails?urlKey=${url_key}&custId=${custId}&guestId=${guestId}`,
{
method: 'GET',
headers: API_HEADER
}
).then(res => res.json())
} catch (error) {
console.log(error)
}
pageinfo = pageinfo.Data.ProdDetails
return { pageinfo }
}

Angular 6 Downloading file from rest api

I have my REST API where I put my pdf file, now I want my angular app to download it on click via my web browser but I got HttpErrorResponse
"Unexpected token % in JSON at position 0"
"SyntaxError: Unexpected token % in JSON at position 0↵ at JSON.parse (
this is my endpoint
#GetMapping("/help/pdf2")
public ResponseEntity<InputStreamResource> getPdf2(){
Resource resource = new ClassPathResource("/pdf-sample.pdf");
long r = 0;
InputStream is=null;
try {
is = resource.getInputStream();
r = resource.contentLength();
} catch (IOException e) {
e.printStackTrace();
}
return ResponseEntity.ok().contentLength(r)
.contentType(MediaType.parseMediaType("application/pdf"))
.body(new InputStreamResource(is));
}
this is my service
getPdf() {
this.authKey = localStorage.getItem('jwt_token');
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/pdf',
'Authorization' : this.authKey,
responseType : 'blob',
Accept : 'application/pdf',
observe : 'response'
})
};
return this.http
.get("http://localhost:9989/api/download/help/pdf2", httpOptions);
}
and invocation
this.downloadService.getPdf()
.subscribe((resultBlob: Blob) => {
var downloadURL = URL.createObjectURL(resultBlob);
window.open(downloadURL);});
I resolved it as follows:
// header.component.ts
this.downloadService.getPdf().subscribe((data) => {
this.blob = new Blob([data], {type: 'application/pdf'});
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = "help.pdf";
link.click();
});
//download.service.ts
getPdf() {
const httpOptions = {
responseType: 'blob' as 'json')
};
return this.http.get(`${this.BASE_URL}/help/pdf`, httpOptions);
}
I solved the issue in this way (please note that I have merged multiple solutions found on stack overflow, but I cannot find the references. Feel free to add them in the comments).
In My service I have:
public getPDF(): Observable<Blob> {
//const options = { responseType: 'blob' }; there is no use of this
let uri = '/my/uri';
// this.http refers to HttpClient. Note here that you cannot use the generic get<Blob> as it does not compile: instead you "choose" the appropriate API in this way.
return this.http.get(uri, { responseType: 'blob' });
}
In the component, I have (this is the part merged from multiple answers):
public showPDF(fileName: string): void {
this.myService.getPDF()
.subscribe(x => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
var newBlob = new Blob([x], { type: "application/pdf" });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob, fileName);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const data = window.URL.createObjectURL(newBlob);
var link = document.createElement('a');
link.href = data;
link.download = fileName;
// this is necessary as link.click() does not work on the latest firefox
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data);
link.remove();
}, 100);
});
}
The code above works in IE, Edge, Chrome and Firefox. However, I don't really like it, as my component is pulluted with browser specific stuff which will surely change over time.
For Angular 12+, I came up with something like this:
this.ApiService
.getFileFromApi()
.pipe(take(1))
.subscribe((response) => {
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(new Blob([response.body], { type: response.body.type }));
const contentDisposition = response.headers.get('content-disposition');
const fileName = contentDisposition.split(';')[1].split('filename')[1].split('=')[1].trim();
downloadLink.download = fileName;
downloadLink.click();
});
The subscribe is on a simple get() with the Angular HttpClient.
// api-service.ts
getFileFromApi(url: string): Observable<HttpResponse<Blob>> {
return this.httpClient.get<Blob>(this.baseApiUrl + url, { observe: 'response', responseType: 'blob' as 'json'});
}
You can do it with angular directives:
#Directive({
selector: '[downloadInvoice]',
exportAs: 'downloadInvoice',
})
export class DownloadInvoiceDirective implements OnDestroy {
#Input() orderNumber: string;
private destroy$: Subject<void> = new Subject<void>();
_loading = false;
constructor(private ref: ElementRef, private api: Api) {}
#HostListener('click')
onClick(): void {
this._loading = true;
this.api.downloadInvoice(this.orderNumber)
.pipe(
takeUntil(this.destroy$),
map(response => new Blob([response], { type: 'application/pdf' })),
)
.subscribe((pdf: Blob) => {
this.ref.nativeElement.href = window.URL.createObjectURL(pdf);
this.ref.nativeElement.click();
});
}
// your loading custom class
#HostBinding('class.btn-loading') get loading() {
return this._loading;
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
In the template:
<a
downloadInvoice
[orderNumber]="order.number"
class="btn-show-invoice"
>
Show invoice
</a>
My answer is based on #Yennefer's, but I wanted to use the file name from the server since I didn't have it in my FE. I used the Content-Disposition header to transmit this, since that is what the browser uses for a direct download.
First, I needed access to the headers from the request (notice the get method options object):
public getFile(): Observable<HttpResponse<Blob>> {
let uri = '/my/uri';
return this.http.get(uri, { responseType: 'blob', observe: 'response' });
}
Next, I needed to extract the file name from the header.
public getFileName(res: HttpResponse<any>): string {
const disposition = res.headers.get('Content-Disposition');
if (!disposition) {
// either the disposition was not sent, or is not accessible
// (see CORS Access-Control-Expose-Headers)
return null;
}
const utf8FilenameRegex = /filename\*=UTF-8''([\w%\-\.]+)(?:; |$)/;
const asciiFilenameRegex = /filename=(["'])(.*?[^\\])\1(?:; |$)/;
let fileName: string = null;
if (utf8FilenameRegex.test(disposition)) {
fileName = decodeURIComponent(utf8FilenameRegex.exec(disposition)[1]);
} else {
const matches = asciiFilenameRegex.exec(disposition);
if (matches != null && matches[2]) {
fileName = matches[2];
}
}
return fileName;
}
This method checks for both ascii and utf-8 encoded file names, prefering utf-8.
Once I have the file name, I can update the download property of the link object (in #Yennifer's answer, that's the lines link.download = 'FileName.ext' and window.navigator.msSaveOrOpenBlob(newBlob, 'FileName.ext');)
A couple of notes on this code:
Content-Disposition is not in the default CORS whitelist, so it may not be accessible from the response object based on the your server's configuration. If this is the case, in the response server, set the header Access-Control-Expose-Headers to include Content-Disposition.
Some browsers will further clean up file names. My version of chrome seems to replace : and " with underscores. I'm sure there are others but that's out of scope.
//Step: 1
//Base Service
this.getPDF() {
return this.http.get(environment.baseUrl + apiUrl, {
responseType: 'blob',
headers: new HttpHeaders({
'Access-Control-Allow-Origin': '*',
'Authorization': localStorage.getItem('AccessToken') || ''
})
});
}
//Step: 2
//downloadService
getReceipt() {
return new Promise((resolve, reject) => {
try {
// {
const apiName = 'js/getReceipt/type/10/id/2';
this.getPDF(apiName).subscribe((data) => {
if (data !== null && data !== undefined) {
resolve(data);
} else {
reject();
}
}, (error) => {
console.log('ERROR STATUS', error.status);
reject(error);
});
} catch (error) {
reject(error);
}
});
}
//Step 3:
//Component
getReceipt().subscribe((respect: any) => {
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement(‘a’);
link.href = downloadURL;
link.download = “sample.pdf";
link.click();
});
This also works in IE and Chrome, almost the same answer only for other browsers the answer is a bit shorter.
getPdf(url: string): void {
this.invoiceService.getPdf(url).subscribe(response => {
// It is necessary to create a new blob object with mime-type explicitly set
// otherwise only Chrome works like it should
const newBlob = new Blob([(response)], { type: 'application/pdf' });
// IE doesn't allow using a blob object directly as link href
// instead it is necessary to use msSaveOrOpenBlob
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(newBlob);
return;
}
// For other browsers:
// Create a link pointing to the ObjectURL containing the blob.
const downloadURL = URL.createObjectURL(newBlob);
window.open(downloadURL);
});
}

How to translate superagent to axios?

I have some upload working for superagent. It involves posting to an api for cloudinary. My question is how do I do the same thing with axios. I'm not sure what superagent.attach and superagent.field relate to in axios.
Basically when I make the post request I need to attach all these fields to the request or else I get bad request and I want to do this in axios not superagent as I am switching over to axios.
Here are all the params:
const image = files[0];
const cloudName = 'tbaustin';
const url = `https://api.cloudinary.com/v1_1/${cloudName}/image/upload`;
const timestamp = Date.now()/1000;
const uploadPreset = 'cnh7rzwp';
const paramsStr = `timestamp=${timestamp}&upload_preset=${uploadPreset}ORor-6scjYwQGpNBvMW2HGMkc8k`;
const signature = sha1(paramsStr);
const params = {
'api_key': '177287448318217',
'timestamp': timestamp,
'upload_preset': uploadPreset,
'signature': signature
}
Here is the superagent post request:
let uploadRequest = superagent.post(url)
uploadRequest.attach('file', image);
Object.keys(params).forEach((key) => {
uploadRequest.field(key, params[key]);
});
uploadRequest.end((err, res) => {
if(err) {
alert(err);
return
}
You would need to use FromData as follows:
var url = `https://api.cloudinary.com/v1_1/${cloudName}/upload`;
var fd = new FormData();
fd.append("upload_preset", unsignedUploadPreset);
fd.append("tags", "browser_upload"); // Optional - add tag for image admin in Cloudinary
fd.append("signature", signature);
fd.append("file", file);
const config = {
headers: { "X-Requested-With": "XMLHttpRequest" },
onUploadProgress: function(progressEvent) {
// Do something with the native progress event
}
};
axios.post(url, fd, config)
.then(function (res) {
// File uploaded successfully
console.log(res.data);
})
.catch(function (err) {
console.error('err', err);
});
See full example here