Plugin errors after upgrading appolo-server-express from v2 to v3 - sentry

I'm using the plugin example from one of Sentry's help pages. It was working fine - but after upgrading to apollo-server-express 3 I'm getting the following typescript error. I don't understand what I have to do in order to fix the error.
TS2322: Type '{ requestDidStart(: any): { didEncounterErrors(ctx: any): void; }; }[]' is not assignable to type 'PluginDefinition[]'.   Type '{ requestDidStart(: any): { didEncounterErrors(ctx: any): void; }; }' is not assignable to type 'PluginDefinition'.     Type '{ requestDidStart(_: any): { didEncounterErrors(ctx: any): void; }; }' is not assignable to type 'ApolloServerPlugin<Record<string, any>>'.       The types returned by 'requestDidStart(...)' are incompatible between these types.         Type '{ didEncounterErrors(ctx: any): void; }' is missing the following properties from type 'Promise<void | GraphQLRequestListener<Record<string, any>>>': then, catch, [Symbol.toStringTag], finally types.d.ts(45, 5): The expected type comes from property 'plugins' which is declared here on type 'Config'
Here's the plugin:
const plugins = [
{
requestDidStart(_:any) {
/* Within this returned object, define functions that respond
to request-specific lifecycle events. */
return {
didEncounterErrors(ctx:any ) {
// If we couldn't parse the operation, don't
// do anything here
if (!ctx.operation) {
return
}
for (const err of ctx.errors) {
// Only report internal server errors,
// all errors extending ApolloError should be user-facing
if (err instanceof ApolloError) {
continue;
}
// Add scoped report details and send to Sentry
Sentry.withScope(scope => {
// Annotate whether failing operation was query/mutation/subscription
scope.setTag("kind", ctx.operation.operation);
// Log query and variables as extras (make sure to strip out sensitive data!)
scope.setExtra("query", ctx.request.query);
scope.setExtra("variables", ctx.request.variables);
if (err.path) {
// We can also add the path as breadcrumb
scope.addBreadcrumb({
category: "query-path",
message: err.path.join(" > "),
level: Sentry.Severity.Debug
});
}
const transactionId = ctx.request.http.headers.get(
"x-transaction-id"
);
if (transactionId) {
scope.setTransaction(transactionId);
}
Sentry.captureException(err);
});
}
}
};
}
}
]

Add the async keyword before requestDidStart and before didEncounterErrors
Looks like the expected return result has to be a Promise now.

Related

How to use custom formatters in json2csv

I've read through the documentation on how to use the built in formatters but Im facing some issues..
Here's my code:
import { Parser, stringFormatter } from "json2csv";
const jsonConvertToCsv = (jsonData: any) => {
const csvOpts = {
formatters: {
string: stringFormatter()
},
}
const json2csvParser = new Parser(csvOpts);
return json2csvParser.parse(jsonData);
}
But somehow it doesnt seem to be able to instantiate the in built formatter that I imported. I get the error that the stringFormatter is not a function but the documentation shows that it can be imported??
https://github.com/zemirco/json2csv

Prae:Wrapper: need to use iter_mut of interior Vec but Prae:Wrapper only provides immutable access

I'm using the prae crate for validation and the following function gives me errors:
fn advance_rotors(&mut self) {
self.rotors.get()[0].rotate();
let mut iterhandle = self.rotors.iter_mut().peekable(); // Error at iter_mut() #0599
while let Some(el) = iterhandle.next() {
match iterhandle.peek_mut() {
Some(next_rotor) => match el.should_advance_next() {
true => {
next_rotor.rotate(); // This line requires mutable access to next_rotor
}
false => (),
},
None => (),
}
}
}
and the definition of my struct here:
pub struct Enigma {
reflector: Reflector,
rotors: RotorConfig, // Only mutable via getter and setter functions
}
the struct of interest here is RotorConfig which is generated using the define! macro from prae. Here's the code:
prae::define! {
#[derive(Debug)]
RotorConfig: Vec<Rotor>; // I need to be able to call the rotate method of each rotor in this vec. This requires mutability
validate(RotorConfigError) |config| {
match config.len(){
3..=4 => (),
_ => return Err(RotorConfigError::Size)
}
match config.iter().unique().count(){
3..=4 =>(),
_ => return Err(RotorConfigError::Duplicate)
}
Ok(())
};
}
the issue stems from the fact that prae only allows for immutable access to the internal representation via getter and setter functions so as to ensure the validity of the values inside. As you can see in my advance_rotors function I wrote before implementing validation I'm getting an error because I need to call rotor.rotate mutably. I'm at a loss as to how to accomplish this
After posting this I realized that I can simply provide interior mutability by using the following impl block
impl RotorConfig{
fn advance_rotors(&mut self)
{
self.0[0].rotate();
let mut iterhandle = self.0.iter_mut().peekable();
while let Some(el) = iterhandle.next() {
match iterhandle.peek_mut() {
Some(next_rotor) => match el.should_advance_next() {
true => {
next_rotor.rotate();
}
false => (),
},
None => (),
}
}
}
}
As you can see the function largely remains unchanged except that we replace self.rotors with self.0

rxswift bind(onNext: VS subscribe(onNext:

I have 2 questions:
What difference between 'bind(onNext:' and 'subscribe(onNext:'?
struct Info {
var index: Int?
var data: String?
}
let infoData: BehaviorRelay<Info> = BehaviorRelay<Info>(value: Info())
var osInfo: Observable<String> { return self.infoData.map({ return $0.data }).distinctUntilChanged() }
osInfo.bind { (target) in
print("bind!")
}.disposed(by: self.disposeBag)
osInfo.subscribe { (target) in
print("subscribe!")
}
.disposed(by: self.disposeBag)
a has no asObservable(), but well executable. What is difference a and b?
a. var osInfo: Observable<String> { return self.infoData.map({ return $0.data }).distinctUntilChanged() }
b. var osInfo: Observable<String> { return self.infoData.asObservable().map({ return $0.data }).distinctUntilChanged() }
What difference between 'bind(onNext:' and 'subscribe(onNext:'?
If we check out implementation of bind(...) we found that it does nothing else but just uses subscribe(...) underhood and crashes in Debug with error:
/**
Subscribes an element handler to an observable sequence.
In case error occurs in debug mode, `fatalError` will be raised.
In case error occurs in release mode, `error` will be logged.
- parameter onNext: Action to invoke for each element in the observable sequence.
- returns: Subscription object used to unsubscribe from the observable sequence.
*/
public func bind(onNext: #escaping (E) -> Void) -> Disposable {
return subscribe(onNext: onNext, onError: { error in
rxFatalErrorInDebug("Binding error: \(error)")
})
}
By using bind(onNext) you can express that stream should never emit error and you interested only in item events.
So you should use subscribe(onNext:...) when you interested in error / complete / disposed events and bind(onNext...) otherwise. But since it is part of RxCocoa and not RxSwift I usually use subscribe everywhere.
a has no asObservable(), but well executable. What is difference a and b?
map(...) is function declared on ObservableType and returning new Observable
Let's start from ObservableType.
ObservableType is protocol that require only one method: subscribe(...), this allow him to create default implementation of func asObservable().
For you it means that you can create Observable from any type that conform to ObservableType.
/// Represents a push style sequence.
public protocol ObservableType : ObservableConvertibleType {
func subscribe<O: ObserverType>(_ observer: O) -> Disposable where O.E == E
}
extension ObservableType {
/// Default implementation of converting `ObservableType` to `Observable`.
public func asObservable() -> Observable<E> {
// temporary workaround
//return Observable.create(subscribe: self.subscribe)
return Observable.create { o in
return self.subscribe(o)
}
}
}
So each time you call asObservable() underhood RxSwift just creates new Observable wrapper around your stream.
And if you check source of BehaviourRelay you will find that it conform to ObservableType as well. So you can create Observable from it anytime:
public final class BehaviorRelay<Element>: ObservableType { ... }
Now lets check map function:
extension ObservableType {
/**
Projects each element of an observable sequence into a new form.
- seealso: [map operator on reactivex.io](http://reactivex.io/documentation/operators/map.html)
- parameter transform: A transform function to apply to each source element.
- returns: An observable sequence whose elements are the result of invoking the transform function on each element of source.
*/
public func map<R>(_ transform: #escaping (E) throws -> R)
-> Observable<R> {
return self.asObservable().composeMap(transform)
}
}
As expected map just call asObservable() inside and operate on new Observable.
If we "unwrap" map call we will get:
var osInfoA: Observable<String> {
return infoData
.asObservable()
.composeMap { $0.data }
.distinctUntilChanged()
}
var osInfoB: Observable<String> {
return infoData
.asObservable()
.asObservable()
.composeMap { $0.data }
.distinctUntilChanged()
}
Sure it will not compile since composeMap is internal function but you got main idea.
Calling asObservable before other operators is redundant (most operators defined on ObservableType) and just add small overhead.

Reconnect to source and continue from last emitted value

I'm trying to figure out how to implement reconnect to observable after a transient failure, to continue from a last emitted value.
Assume I have the following method:
interface MyQuery {
fromId: number;
toId: number;
}
interface MyItem {
id: number;
val: string;
}
function observeUnstable(query: MyQuery): Observable<MyItem>;
The method observableUnstable lets to subscribe to a stream which emits values and may emit the following error in case of intermittent connection failure:
class DisconnectedError extends Error;
I want to compose a new observable which would wrap the original observable above and have transparent resubscribe from the position at which the previous subscription has failed.
The data types are going to be opaque, so I would want to make the reconnection logic generic, probably as an operator which would accept a high order selector function:
let startQuery = { fromId: 1, toId: 10 };
let reconnectable = observeUnstable(startQuery)
.lift(new ReconnectOperator<MyItem>((err, lastValue?) => {
if (err instanceof DisconnectedError) {
// This error indicates that we've been disconnected,
// resubscribing from the place we have stopped
let continueQuery = {
fromId: lastValue ? lastValue.id + 1 : startQuery.fromId,
toId: startQuery.toId
};
return observeUnstable(continueQuery);
} else {
// Rethrowing error we don't expect
throw err;
}
}));
Here are my ReconnectOperator and ReconnectSubscriber:
class ReconnectOperator<T> implements Operator<T, T> {
constructor(private handler: (err: any, lastValue?: T) => Observable<T>) {
}
call(subscriber: Subscriber<T>, source: any): any {
return source.subscribe(new ReconnectSubscriber(subscriber, this.handler));
}
}
class ReconnectSubscriber<T> extends Subscriber<T> {
private lastValue?: T;
constructor(destination: Subscriber<T>, private handler: (err: any, lastValue?: T) => Observable<T>) {
super(destination);
}
protected _next(value: T) {
this.lastValue = value;
super._next(value);
}
error(err: any) {
if (!this.isStopped) {
let result: Observable<T>;
try {
result = this.handler(err, this.lastValue);
} catch (err2) {
super.error(err2);
return;
}
// TODO: ???
result.subscribe(this._unsubscribeAndRecycle());
// this._unsubscribeAndRecycle();
//this.source.subscribe(result);
//this.add(subscribeToResult(this, result));
}
}
}
This subscriber is very similar to CatchSubscriber with only one difference is that CatchSubscriber returns original observable in selector method, in my case I want to return last value so the selector could use it to compose a brand new observable rather than reusing the original one.
But I messed with resubscribe logic somehow so the resulting observable never returns complete for small amount of test values, and crashes with stack overflow for bigger amount of test values.
Also, my idea here is to implement a new operator but if it's possible to implement it in a single method just using composition of existing operators, in a generic way, that would be even better :)
Example of an alternative method but without operator:
function observeStable<T, Q>(
query: Q,
continueQueryFunc: (query: Q, lastValue?: T) => Observable<T>
): Observable<T> {
return observeUnstable<T>(query).catch((err, ???) =>
if (err instanceof DisconnectedError) {
let lastValue = ???
let continueQuery = continueQueryFunc(query, lastValue);
return observeUnstable(continueQuery);
} else {
throw err;
}
);
}

"Argument labels '(options:)' do not match any available overloads" occurs in PagingMenuController

I use PagingMenuController 2.0.0 in my project using swift3.
I have a problem when I write following codes.
These codes are copied from README of PagingMenuController.
An error "Argument labels '(options:)' do not match any available overloads" occurs in the last line.
struct MenuItem1: MenuItemViewCustomizable {}
struct MenuItem2: MenuItemViewCustomizable {}
struct MenuOptions: MenuViewCustomizable {
var itemsOptions: [MenuItemViewCustomizable] {
return [MenuItem1(), MenuItem2()]
}
}
struct PagingMenuOptions: PagingMenuControllerCustomizable {
var componentType: ComponentType {
return .all(menuOptions: MenuOptions(), pagingControllers: [UIViewController(), UIViewController()])
}
}
let options = PagingMenuOptions()
let pagingMenuController = PagingMenuController(options: options)

Resources