I'm trying to use apollo RESTDataSource to wrap my rest api. I need to pass some headers to the api call.
I'm following the example from the docs: https://www.apollographql.com/docs/apollo-server/features/data-sources#intercepting-fetches
This is my code:
willSendRequest(request: RequestOptions) {
console.log(`request 1: ${JSON.stringify(request)}`);
request.headers.set('Authorization', this.context.authorization);
console.log(`request 2: ${JSON.stringify(request)}`);
}
I'm expecting the headers to contain 'Authorization'. But it's always empty.
The log from the above code:
request 1: {"method":"POST","path":"partnerinvoices","body":{"command": "input","params":{},"headers":{}}
request 2: {"method":"POST","path":"partnerinvoices","body":{"command":"input","params":{},"headers":{}}
I can override body and params in willSendRequest method without any problem.
There are few ways that you could implement this,
within your Datasources class that extends RESTDataSource set the headers before request is being made
willSendRequest(request) {
request.headers.set('Authorization', 'Bearer .....')
}
or as a third argument in the datasource method (post, get, put, ...)
this.post('endpoint', {}, { headers: { 'Authorization': 'Bearer ...' } })
It is super important, if you are using Typescript, that you match the original signature of the willSendRequest method:
protected willSendRequest?(request: RequestOptions): ValueOrPromise<void>;
(Link to the docs)
So, make sure the method looks like this:
protected willSendRequest?(request: RequestOptions): ValueOrPromise<void> {
request.headers.set("Authorization", this.context.authorization);
}
You need to use request.headers.get('Authorization') to get your desired data. Using JSON.stringify will not give you the headers values as it is not a object literal.
willSendRequest(request: RequestOptions) {
console.log(`request 1: ${request.headers.get('Authorization')}`);
request.headers.set('Authorization', this.context.authorization);
console.log(`request 2: ${request.headers.get('Authorization')}`);
}
Related
I have an assignment to: use the method GET to fetch api info from http://api.example.com/. I'm also told to only use: Javascript/Reactjs
However, everywhere I search, I can only fetch the data. Are these two the same thing? Or am I looking at the wrong tutorials?
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
isLoaded: false,
}
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json,
})
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>
}
else {
return (
<div className="App">
<ul>
{items.map(item => (
<li key={item.uid}>
Name: {item.name} | Email:{item.email}
</li>
))};
</ul>
</div>
);
}
}
}
export default App;
they are interchangeable, as a technical jargon from the field, "get data from api" and "fetch data from the api" means the same thing.
in javascript, nowadays, we use the Fetch API to interact with an api, using HTTP request methods like GET, HEAD, POST, DELETE.
unfortunately i don't know a page or repository listing these jargons
Fetch is a javascript API used for making XHR requests across the web (normally for interacting with an API).
let promise = fetch(url, {
method: "GET", // POST, PUT, DELETE, etc.
headers: {
// the content type header value is usually auto-set
// depending on the request body
"Content-Type": "text/plain;charset=UTF-8"
},
body: undefined // string, FormData, Blob, BufferSource, or URLSearchParams
referrer: "about:client", // or "" to send no Referer header,
// or an url from the current origin
referrerPolicy: "no-referrer-when-downgrade", // no-referrer, origin, same-origin...
mode: "cors", // same-origin, no-cors
credentials: "same-origin", // omit, include
cache: "default", // no-store, reload, no-cache, force-cache, or only-if-cached
redirect: "follow", // manual, error
integrity: "", // a hash, like "sha256-abcdef1234567890"
keepalive: false, // true
signal: undefined, // AbortController to abort request
window: window // null
});
But GET is an HTTP verb. The primary or most-commonly-used HTTP verbs (or methods, as they are properly called) are POST, GET, PUT, PATCH, and DELETE. These correspond to create, read, update, and delete (or CRUD) operations, respectively.
To understand more about these methods read Architectural Styles and
the Design of Network-based Software Architectures by Dr Roy Fielding or popularly know as roy fielding paper which describes about the RESTful nature of the web and the use of these HTTP verbs. https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
I need to pass an id obtained from an api call to invoke another api call, cant get it to work!
can anyone help?
The second api which will return and image call does not work and is greyed out in vs code
if anyone can help with an example, i would be greatful
currentResult: any;
getData(){
this.showLoading();
const headers = {
"x-api-key":'',
'Content-Type': 'application/json',
"Access-Control-Allow-Origin":"*",
"x-requested-with": "xmlhttprequest",
/* 'Authorization': `Bearer ${this.sygicBearerToken}` */
}
return this.http.get(
this.ProxyUrl1+'https://api.sygictravelapi.com/1.2/en/places/list?parents=city:2&categories=discovering&limit=10', { headers: headers },
)
.pipe(tap (value => {
this.loadingController.dismiss();
console.log(value);
}))
this.http.get(
this.ProxyUrl1+'https://api.sygictravelapi.com/1.2/en/places/{id}/media',{ headers: headers},)
.pipe(tap (value => {
this.loadingController.dismiss();
console.log(value);
})
);
}
Since you have a return statement with the first this.http.get, anything after the return statement will not run, so it is grayed out.
First: the second API call is greyed out because its written after a return call.
in order to call an additional API call using the result of the first call,
you can use RXJS switchMap
this will help you get a sequential requests, one after the other.
for exmaple example:
get data() {
return this.http.get('http://firstAPI').pipe(
switchMap(id => this.http.get(`http://secondAPI/${id}`))
);
}
the first API call results "id" is passed to the second http call.
read more: RXJS switchMap
I am using RestAPI from Wikibase which in turn use Hyperswitch framework.
In the example code of its yaml file, there is a case to choose to return the response or not depend on the status code
x-request-handler:
- storage:
request:
method: get
headers:
cache-control: '{{cache-control}}'
# cache-control: "no-cache"
uri: /{domain}/sys/key_value/page_summary3/{request.params.title}
catch:
status: 404
return_if:
# Typical case: Return straight from storage.
status: '2xx'
return:
But I would like to return depend on a value found on the response body, say success: 1. How can I do that?
return_if:
'{{storage.body.success}}': 1
maybe? That syntax works in values, I don't know if it works in keys. You can always handle the request manually though: use operationId instead of x-request-handler, and then have a function like
function storage(hyper, req) {
return hyper.get(...).then((res) => {
if (res.body.success === 1) {
return res;
}
return {...};
});
}
and export it with the operation ID you chose.
Is it possible to alter the headers of the Request object that is received by the fetch event?
Two attempts:
Modify existing headers:
self.addEventListener('fetch', function (event) {
event.request.headers.set("foo", "bar");
event.respondWith(fetch(event.request));
});
Fails with Failed to execute 'set' on 'Headers': Headers are immutable.
Create new Request object:
self.addEventListener('fetch', function (event) {
var req = new Request(event.request, {
headers: { "foo": "bar" }
});
event.respondWith(fetch(req));
});
Fails with Failed to construct 'Request': Cannot construct a Request with a Request whose mode is 'navigate' and a non-empty RequestInit.
(See also How to alter the headers of a Response?)
Creating a new request object works as long as you set all the options:
// request is event.request sent by browser here
var req = new Request(request.url, {
method: request.method,
headers: request.headers,
mode: 'same-origin', // need to set this properly
credentials: request.credentials,
redirect: 'manual' // let browser handle redirects
});
You cannot use the original mode if it is navigate (that's why you were getting an exception) and you probably want to pass redirection back to browser to let it change its URL instead of letting fetch handle it.
Make sure you don't set body on GET requests - fetch does not like it, but browsers sometimes generate GET requests with the body when responding to redirects from POST requests. fetch does not like it.
You can create a new request based on the original one and override the headers:
new Request(originalRequest, {
headers: {
...originalRequest.headers,
foo: 'bar'
}
})
See also: https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
Have you tried with a solution similar to the one in the question you mention (How to alter the headers of a Response?)?
In the Service Worker Cookbook, we're manually copying Request objects to store them in IndexedDB (https://serviceworke.rs/request-deferrer_service-worker_doc.html). It's for a different reason (we wanted to store them in a Cache, but we can't store POST requests because of https://github.com/slightlyoff/ServiceWorker/issues/693), but it should be applicable for what you want to do as well.
// Serialize is a little bit convolved due to headers is not a simple object.
function serialize(request) {
var headers = {};
// `for(... of ...)` is ES6 notation but current browsers supporting SW, support this
// notation as well and this is the only way of retrieving all the headers.
for (var entry of request.headers.entries()) {
headers[entry[0]] = entry[1];
}
var serialized = {
url: request.url,
headers: headers,
method: request.method,
mode: request.mode,
credentials: request.credentials,
cache: request.cache,
redirect: request.redirect,
referrer: request.referrer
};
// Only if method is not `GET` or `HEAD` is the request allowed to have body.
if (request.method !== 'GET' && request.method !== 'HEAD') {
return request.clone().text().then(function(body) {
serialized.body = body;
return Promise.resolve(serialized);
});
}
return Promise.resolve(serialized);
}
// Compared, deserialize is pretty simple.
function deserialize(data) {
return Promise.resolve(new Request(data.url, data));
}
If future readers have a need to also delete keys in the immutable Request/Response headers and also want high fidelity to the immutable headers, you can effectively clone the Header object:
const mutableHeaders = new Headers();
immutableheaders.forEach((value, key, parent) => mutableHeaders.set(key, value));
mutableHeaders.delete('content-encoding');
mutableHeaders.delete('vary');
mutableHeaders['host'] = 'example.com';
// etc.
You can then create a new Request and pass in your mutableHeaders.
This is preferred to the accepted answer because if you have the need to proxy a Request, you don't want to manually specify every possible header while including the Cloudflare, AWS, Azure, Google, etc. custom CDN headers.
Background Info
The reason why the headers are immutable or read-only in a Request is because:
interface Request extends Body {
readonly cache: RequestCache;
readonly credentials: RequestCredentials;
readonly destination: RequestDestination;
readonly headers: Headers;
readonly integrity: string;
...
The interface for Headers is:
interface Headers {
append(name: string, value: string): void;
delete(name: string): void;
get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
forEach(callbackfn: (value: string, key: string, parent: Headers) => void, thisArg?: any): void;
}
I have an'ajax request done with jquery, and a Symfony2 controller that responds to this request with a json (if understand that is an'ajax request) or with a response (if not).
Ajax request:
$.get('path/to/bla/bla/', function () {
// do something ...
})
Symfony's Action
use Symfony\Component\HttpFoundation\Request;
class FooController {
public function barAction(Request $request) {
if($request->isXmlHttpRequest()) {
// json response
} else {
// normal response
}
}
}
Can I fix the header "X-Requested-With" of jquery $.get to XMLHttpRequest?
HttpFoundation/Request::isXmlHttpRequest() {
return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
}
Yes, you can use $.ajaxSetup to change the default header option for X-Requested-With.
$.ajaxSetup({
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
Note however that XMLHttpRequest is already the default setting.
If you're trying to do this for a JSONP request, that simply isn't possible.
in this situation the only thing that changes is the view of the controller, for a simple case I would do the following
//...
/**
* #Route("/index.{format}", defaults={"format" = "html"})
*/
public function indexAction($format)
{
return $this->render("ByteinCoffeeWebBundle:Frontend/User:index.$format.twig");
}
//...
but if this is a common thing in your application i guess better take a look in this package: https://github.com/FriendsOfSymfony/FOSRestBundle