Проверьте данные ответа API с интерфейсом в Typescript Angular - PullRequest
2 голосов
/ 12 февраля 2020

У меня есть приложение, которое, когда пользователь входит в систему, получает в ответ некоторые данные, но если ответ не соответствует ожиданиям, приложение вылетает.

Позвольте мне показать вам следующее:

Я создал интерфейс, чтобы сообщить Typescript ожидаемые данные.

export interface AuthResponseData {
  token: string;
  expires: string;
  role: number;
}

Затем я создал метод для отправки данных для входа на сервер.

login(user: string, password: string){
  return this.http.post<AuthResponseData>(
    'https://localhost:44344/api/auth', { user: user, pwd: password }
  ).pipe(
    catchError(this.handleError),
    tap(resData => { this.handleAuthentication(resData.token, resData.expires, resData.role)})
  );
}

Я был ожидая, что если ответ от сервера не будет соответствовать интерфейсу, Angular будет перенаправлен на catchError. Но не бывает

Теперь мой вопрос : есть ли способ проверить, равен ли ответ API интерфейсу, и выдать ошибку, если нет. Или то, что я спрашиваю, невозможно?

ОБНОВЛЕНИЕ:

После поиска я обнаружил, что интерфейсы исчезают во время выполнения, поэтому нет никакого способа сравнить ответ API с интерфейсом (насколько мне известно). Но я продолжаю искать способ проверить ответ API динамически c. Я думаю, что это не совсем безопасно, в зависимости от ответа API, чтобы быть всегда правильным. Поэтому я должен проверить ответ API. Как я могу это сделать?

Надеюсь, вы можете мне помочь, спасибо:)

Ответы [ 6 ]

2 голосов
/ 21 февраля 2020

Вы можете использовать функцию обещания и thenable (), чтобы перехватить ошибку, если ваш ответ API не соответствует вашему требованию.

login(user: string, password: string){
        return this.http.post('https://localhost:44344/api/auth', { user: user, pwd: password })
        .pipe(map(response => {
            this.checkForValidResponse(response)
            .then( onResolve =>{
                //Came here is your response is according to your requirements
            })
            .catch(onReject =>{
                //Catch the error and treat it as error if your resposne is not according to your requirements
            });
        }));            
    }
    checkForValidResponse(responseOfApi){
        return new Promise((resolve, reject)=>{
            //Your Code for To Check wether API response is Valid OR not . 

            //If YOur API reponse is valid then **
            resolve(Your message to send back)

            //IF your API resopnse is invalid
            reject(Your message to send back)
        })
    }

Надеюсь, это то, что вы ищете.

1 голос
/ 20 февраля 2020

Как вы уже заметили, interface - это чисто TypeScript, он не существует в JavaScript и не эмулируется каким-либо образом (точно так же как private, protected, public и некоторые другие вещи). Проверка типов в TypeScript позволяет получить логику "fast fast" c (вам не нужно запускать приложение, чтобы заметить, что ваш собственный код или сторонняя библиотека используется неправильно, во время компиляции происходит сбой).

Ваше Angular приложение - это просто пользовательский интерфейс, в нем нет критических операций (они должны находиться в вашем бэкэнде), поэтому я не думаю, что будет хорошей идеей выдавать ошибку из-за несоответствия типов вместо того, чтобы просто пытаться удовлетворить пользователя как можно больше. По моему мнению, бэкэнд должен проверять входные данные клиента, а клиент должен пытаться адаптироваться к бэкэнд-сервису.

При этом здесь есть черновик для проверки JSON https://json-schema.org/ и некоторые библиотеки реализуют его (например: https://github.com/epoberezkin/ajv). Это позволит вам получить желаемое поведение.

1 голос
/ 20 февраля 2020

В вашем выпуске есть 3 вопроса плюс один дополнительный вопрос (в конце) для лучшего понимания:

Я спрашиваю об этом, потому что если у меня есть конечная точка, которая возвращает 100 атрибутов Мне придется проверять 100 вручную, верно?

Это правильный способ написать interface s на основе возвращенных моделей из ответов API. если одна конечная точка возвращает модель, содержащую 100 свойств, правильным способом будет написать соответствующий Typescript interface с такими же свойствами, возможно, с помощью инструмента, подобного json2ts . Это позволяет проверка типов и предотвращает нежелательные ошибки программирования без каких-либо затрат, поскольку interface s не существует в времени выполнения .

Есть ли способ проверить, равен ли ответ API интерфейсу и выдать ошибку, если нет. Или то, что я спрашиваю, невозможно?

Вы можете проверить значение ключевого свойства внутри tap, чтобы обнаружить условие (null).

I ожидал, что если ответ от сервера не будет соответствовать интерфейсу, то Angular перенаправит на catchError. Но этого не происходит.

interface несоответствие не будет рассматриваться как Rx JS s catchError. Он срабатывает, когда возникает ошибка запроса, например, 400 (неверный запрос). Обратите внимание, что Проверка типа означает, что как только вы объявите переменную определенного типа, задача компилятора - убедиться, что ей назначены только значения этого типа (или значения, которые являются подчиненными). -типы этого типа).

Есть ли способ иметь динамическую c модель для всех конечных точек?

Некоторые люди используют скобочные обозначения чтобы извлечь значения ответа. Обозначения в скобках и точечные обозначения функционально эквивалентны в JavaScript, но не совпадают в TypeScript. TypeScript менее строг с обозначениями в скобках, и такое поведение является намеренным, чтобы предложить какой-то бэкдор. Я не предлагаю такой способ, который делает код грязным и ошибочным.

1 голос
/ 19 февраля 2020

Чтобы проверить правильность ответа API, используйте класс вместо интерфейса и задайте ему функцию isValid и / или проверьте данные в конструкторе.

например,

interface IAuthResponseData {
  token: string;
  expires: string;
  role: string;
}

class AuthResponseData implements IAuthResponseData {
  public token: string;
  public expires: string;
  private __expires: Date;
  public role: string;

  public constructor(data: IAuthResponseData) {
    this.token = data.token;
    this.expires = data.expires;
    this.__expires = new Date(data.expires);
    this.role = data.role;
    if (!this.isValid()) {
      throw new Error("Invalid Parameters")
    }
  }

  public isValid(): boolean {
    // simple equals check against null is also true when the value is undefined
    for (let member in this) {
      if (this[member] == null) {
        return false;
      }
    }
    return true;
  }
}

Не забудьте отловить ошибку и действовать на нее, или оставить проверку вне конструктора и вместо этого проверить после создания объекта и затем действовать на него.

0 голосов
/ 20 февраля 2020

Используйте io-ts . Это дает вам возможность c печатать в IDE и проверять во время выполнения из одного определения. Это сложно получить иначе. В противном случае вам нужно написать конкретные реализации и определений типов, а также механизм для проверки.

0 голосов
/ 19 февраля 2020

Вы можете выдать ошибку, которая будет перехвачена catchError()

login(user: string, password: string){
  return this.http.post<AuthResponseData>(
    'https://localhost:44344/api/auth', { user: user, pwd: password }
  ).pipe(
    map(res => { //  Map should return an observable
      if(!this.isValid()) // isValid() is a hole diffrent story - stucture checking in tyepscript -
          throw new Error('Response structure is not valid.') // Would be catched by catchError
      return res;
    })
    tap(resData => { // tap is for side effects
        this.handleAuthentication(resData.token, resData.expires, resData.role)
    })
    catchError(this.handleError)
  );
}

, теперь для структуры ответа вы можете проверить Проверка типа интерфейса с помощью Typescript

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...