Я учусь на уроке веб-программирования в колледже, и одним из заданий является создание Angular приложения, которое взаимодействует с пользовательским веб-API, который мы написали с использованием ExpressJS. Приложение представляет собой словарь терминов и использует четыре операции CRUD - создание, чтение, обновление, удаление.
Нам предоставили множество примеров кода для создания нашего приложения, поэтому я активно ссылаюсь на это. Моя дилемма связана с POST и PUT. Когда я ввожу данные в форму и отправляю их, консоль браузера показывает сообщение Внутренняя ошибка сервера 500, а API говорит, что полученные значения не определены. Я написал этот API и использовал его для двух предыдущих заданий, одно из которых было REACT App, и оно работало безупречно. Кажется, я не могу понять, является ли мой компонент службы в Angular виновником, или, может быть, я что-то упустил на стороне API.
Вот фрагменты кода, которые я считаю актуальными (ссылки на GitHub и Херою размещали API ниже). Я ценю помощь, и извините, если это долго. Семестр заканчивается, поэтому я должен передать его ко вторнику!
GitHub:
- https://github.com/mdzura/bti425-a2-web-app
- https://github.com/mdzura/bti425-a2-web-api
- https://bti425-a2-web-api.herokuapp.com/api/
сервер. js
/**********************************************************************************
* Web service setup - Packages for handling data and requests. *
**********************************************************************************/
const express = require("express");
const cors = require("cors");
const path = require("path"); // 'path' is for dirctories.
const bodyParser = require('body-parser');
const app = express(); // Links Express for Node Server.
const HTTP_PORT = process.env.PORT || 8080; // Sets the http port to 8080.
const manager = require("./manager.js"); // MongoDB Data model and API request handling.
app.use(bodyParser.json()); // Add support for incoming JSON entities.
app.use(cors()); // Add support for CORS.
app.use(bodyParser.urlencoded({extended: true}));
/*************************************************************************************/
// ********************** Add new **************************//
app.post("/api/term/english/add", function (req, res) {
res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
res.setHeader("Access-Control-Allow-Headers", "Authorization, Cache-Control, Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
console.log("POSTING data");
manager.termEnglishAdd(req.body) // Call the manager method
.then(function(data) {
console.log(data);
res.status(201).json(data);
})
.catch(function(error) {
res.status(500).json({ "message": error });
})
});
/*************************************************************/
// ***************** Edit existing **************************//
app.put("/api/term/english/edit/:id", function (req, res) {
console.log("By ID: " + req.body.id);
if (req.body.id != req.body.id) {
res.status(404).json({ "message": "Resource not found" });
}
else {
manager.termEnglishEdit(req.params) // Call the manager method
.then(function(data) {
res.json(data);
})
.catch(function(error) {
res.status(500).json({ "message": error });
})
}
});
/*************************************************************/
управление. js
const mongoose = require("mongoose");
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
const termEnglishSchema = require("./msc-termEnglish.js");
const definitionSchema = require("./msc-definition");
/******************************************************************************
* Initializes Connection to Database *
******************************************************************************/
let Dictionary; // Collection Properties
module.exports.initialize = function() {
return new Promise(function(resolve, reject) {
let db = mongoose.createConnection("mongodb://localhost:27017/db-a2", { connectTimeoutMS: 5000, useUnifiedTopology: true });
db.on('error', function (err) {
reject(console.log(err.message));
});
db.once('open', function () {
Dictionary = db.model("englishterms", termEnglishSchema, "englishterms");
console.log(Dictionary);
resolve(console.log("Database Connected"));
});
});
};
/*******************************************************************************/
/******************************************************************************
* Add English Term to the Database *
******************************************************************************/
module.exports.termEnglishAdd = function (newItem) {
console.log("Adding English Term to Collection...");
console.log(newItem);
return new Promise(function (resolve, reject) {
//var newTerm = new Dictionary(newItem);
// Find one specific document
Dictionary.create(newItem, function (error, item) {
if (error) {
// Cannot add item
console.log(error.message);
return reject(error.message);
}
//Added object will be returned
console.log(item);
return resolve(item);
});
});
};
/*******************************************************************************/
/******************************************************************************
* Edit existing English Term from the Database *
******************************************************************************/
module.exports.termEnglishEdit = function (changes) {
console.log("Editing English Term in Collection...");
//changes.id has values, but changes.wordEnglish and all the others are coming empty.
console.log("Changes: " + changes.id + ", " + changes.wordEnglish);
return new Promise(function (resolve, reject) {
// Find one specific document
Dictionary.findByIdAndUpdate(changes.id,
{
wordEnglish: changes.wordEnglish,
wordNonEnglish: changes.wordNonEnglish,
wordExpanded: changes.wordExpanded,
languageCode: changes.languageCode,
image: changes.images,
imageType: changes.imageType,
audio: changes.audio,
audioType: changes.audioType,
linkAuthoritative: changes.linkAuthoritative,
linkWikipedia: changes.linkWikipedia,
linkYouTube: changes.linkYouTube,
authorName: changes.authorName,
dateCreated: changes.dateCreated,
dateRevised: changes.dateRevised,
fieldOfStudy: changes.fieldOfStudy,
helpYes: changes.helpYes,
helpNo: changes.helpNo,
definitions: [{
authorName: changes.definitions.authorName,
dateCreated: changes.definitions.dateCreated,
definition: changes.definitions.definition,
quality: changes.definitions.quality,
like: changes.definitions.like
}]
}, function (error, item) {
if (error) {
// Cannot edit item
return reject(console.log(error.message));
}
// Check for an item
if (item) {
// Edited object will be returned
return resolve(item);
} else {
return reject(console.log("Not Found!"));
}
});
});
};
edit-term.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from "@angular/router";
import { DataManagerService } from './data-manager.service';
import { Router } from "@angular/router";
import { NgForm } from '@angular/forms';
import { TermEnglish, Definition } from "./data-class";
import { from } from 'rxjs';
@Component({
selector: 'app-edit-term',
templateUrl: './edit-term.component.html',
styleUrls: ['./edit-term.component.css']
})
export class EditTermComponent implements OnInit {
// Data-holding properties
term: TermEnglish;
changeTerm: TermEnglish;
currentDate = new Date;
constructor(private manager: DataManagerService, private router: Router, private route: ActivatedRoute) {
// Define the user objects
this.changeTerm = new TermEnglish();
}
ngOnInit() {
// If required, go and get data that would be needed to render the form
this.changeTerm.dateRevised = this.currentDate.toLocaleDateString();
// Get the route parameter
let id = this.route.snapshot.params['id'];
// this.manager.englishGetByID(id).subscribe(response => this.changeTerm = response);
this.manager.englishGetByID(id).subscribe(response => {
this.term = response;
this.changeTerm._id = this.term._id;
this.changeTerm.wordEnglish = this.term.wordNonEnglish;
this.changeTerm.wordNonEnglish = this.term.wordNonEnglish;
this.changeTerm.wordExpanded = this.term.wordExpanded;
this.changeTerm.languageCode = this.term.languageCode;
this.changeTerm.image = this.term.image;
this.changeTerm.imageType = this.term.imageType;
this.changeTerm.audio = this.term.audio;
this.changeTerm.audioType = this.term.audioType;
this.changeTerm.linkAuthoritative = this.term.linkAuthoritative;
this.changeTerm.linkWikipedia = this.term.linkWikipedia;
this.changeTerm.linkYouTube = this.term.linkYouTube;
this.changeTerm.authorName = this.term.authorName;
this.changeTerm.dateCreated = this.term.dateCreated;
this.changeTerm.dateRevised = this.term.dateRevised;
this.changeTerm.fieldOfStudy = this.term.fieldOfStudy;
this.changeTerm.helpYes = this.term.helpYes;
this.changeTerm.helpNo = this.term.helpNo;
this.changeTerm.definitions = this.term.definitions;
});
};
// Form submit button handler
editTerm(): void {
// Send request
// this.manager.englishTermEdit(this.term._id, this.changeTerm).subscribe(t => this.changeTerm = t);
this.manager.englishTermEdit(this.changeTerm).subscribe(t => this.changeTerm = t);
this.router.navigate(['/terms']);
}
}
data.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders} from "@angular/common/http";
import { Observable, of } from "rxjs";
import { catchError, tap } from "rxjs/operators";
// Import data model classes, for example...
import { TermEnglish } from "./data-class";
@Injectable({
providedIn: 'root'
})
export class DataManagerService {
// Inject the HttpClient
constructor(private http: HttpClient) { }
// Base URL for the web API
private url: string = 'http://localhost:8080/api';
// Options object for POST and PUT requests
private httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
// Error handler, from the Angular docs
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
console.error(error); // log to console instead
return of(result as T);
};
}
// ############################################################
// Data service operations.
// Add new
englishTermAdd(newItem: TermEnglish): Observable<TermEnglish> {
return this.http.post<TermEnglish>(`${this.url}/term/english/add`, newItem, this.httpOptions)
.pipe(
tap((newItem: TermEnglish) => console.log(`Added Term ${newItem.wordEnglish}`)),
catchError(this.handleError<TermEnglish>('Term add'))
);
}
// Edit existing
englishTermEdit(newItem: TermEnglish): Observable<TermEnglish> {
console.log("EditByID=" + `${this.url}/term/english/edit/${newItem._id}`);
console.log(`Added \n Word: ${newItem.wordEnglish}
\n NonEnglish Word: ${newItem.wordNonEnglish}
\n Expanded Word: ${newItem.wordExpanded}
\n Image: ${newItem.image}
\n Audio: ${newItem.audio}
\n URL: ${newItem.linkAuthoritative}
\n Wiki: ${newItem.linkWikipedia}
\n Youtube: ${newItem.linkYouTube}
\n Author: ${newItem.authorName}
\n Definition: ${newItem.definitions[0].definition}`);
return this.http.put<TermEnglish>(`${this.url}/term/english/edit/${newItem._id}`, newItem, this.httpOptions)
.pipe(
tap((newItem: TermEnglish) => console.log(`Edited item ${newItem.wordEnglish}`)),
catchError(this.handleError<TermEnglish>('Term edit'))
);
}
}