Loome ASP.NET Web API projekt

Programm läheb käima rohelise kolmnurkse nupu kaudu.

Avatud lingi: https://localhost:7170/swagger/index.html

Port on kirja pandud “Properties” kaustas olevas failis “launchSettings.json”, profiles -> projekti_nimi -> applicationUrl taga. Soovi korral võid seda vahetada. Lihtsuse huvides vahetan selle ära:

Lisame uus controller:


Lisatud PrimitiividController
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class PrimitiividController : ControllerBase
{
// GET: primitiivid/hello-world
[HttpGet("hello-world")]
public string HelloWorld()
{
return "Hello world at " + DateTime.Now;
}
}
}
Muudatud port config’is launchSettings.json on 4444

Käivitame projekt ja kontrollime muudatud aadress (GET endpoint): https://localhost:4444/Weather

Esmaste API päringute tegemine
Teeme esimesi päringuid.
Selleks loome uue faili: PrimitiividController, millega saame teha päringuid primitiivsete tüüpidega.

Lõplik kood:
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class PrimitiividController : ControllerBase
{
// GET: primitiivid/hello-world
[HttpGet("hello-world")]
public string HelloWorld()
{
return "Hello world at " + DateTime.Now;
}
// GET: primitiivid/hello-variable/mari
[HttpGet("hello-variable/{nimi}")]
public string HelloVariable(string nimi)
{
return "Hello " + nimi;
}
// GET: primitiivid/add/5/6
[HttpGet("add/{nr1}/{nr2}")]
public int AddNumbers(int nr1, int nr2)
{
return nr1 + nr2;
}
// GET: primitiivid/multiply/5/6
[HttpGet("multiply/{nr1}/{nr2}")]
public int Multiply(int nr1, int nr2)
{
return nr1 * nr2;
}
// GET: primitiivid/do-logs/5
[HttpGet("do-logs/{arv}")]
public void DoLogs(int arv)
{
for (int i = 0; i < arv; i++)
{
Console.WriteLine("See on logi nr " + i);
}
}
}
}
Iseseisvalt loodud meetodid
Primitiivsed kontrollerid:
1. Tee juhuslike numbrite generaator(või Random rand = new Random() abil) – sisestades otspunktile kaks arvu, tagastab programm juhusliku arvu nende vahel
// Harjutus
[HttpGet("random/{arv}/{arv2}")]
public int RandomBetween(int arv, int arv2)
{
Random rnd = new Random();
return rnd.Next(arv, arv2);
}

2.Sisesta sünniaasta otspunktile ning programm tagastab sulle lause, mis ütleb: “oled nii või naa aastat vana (arvutuslikult korrektselt), olenevalt kas sellel aastal on sünnipäev juba olnud”
[HttpGet("find_age/{birthdate}")]
public IActionResult CalculateAge(string birthdate)
{
try
{
if (!DateTime.TryParse(birthdate, out DateTime birthDate))
{
return BadRequest("Invalid date format. Please use a valid date format (e.g., 'yyyy-MM-dd').");
}
var today = DateTime.Today;
int years = today.Year - birthDate.Year;
if (birthDate.Date > today.AddYears(-years))
{
years--;
}
DateTime lastBD = birthDate.AddYears(years);
int days = (today - lastBD).Days;
return Ok(new { Years = years, Days = days });
}
catch (Exception ex)
{
return BadRequest($"Error processing date: {ex.Message}");
}
}

Mudeli koostamine
Teeme valmis veebipoe toote mudeli. Esmalt teeme kausta “Models” ja seejärel paneme uuele failile nimeks “Toode”.
Lisame Toode mudel:
public class Toode
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public bool IsActive { get; set; }
public Toode(int id, string name, double price, bool isActive)
{
Id = id;
Name = name;
Price = price;
IsActive = isActive;
}
}
API päringud mudeliga
Lisame Toode Controller:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class ToodeController : ControllerBase
{
private static Toode _toode = new Toode(1, "Koola", 1.5, true);
// GET: toode
[HttpGet]
public Toode GetToode()
{
return _toode;
}
// GET: toode/suurenda-hinda
[HttpGet("suurenda-hinda")]
public Toode SuurendaHinda()
{
_toode.Price = _toode.Price + 1;
return _toode;
}
}
}
Harjutused:
- Tee uus API otspunkt, mis käivitades muudab toote aktiivsust
- Tee uus API otspunkt, mis käivitades muudab toote nime. Võta selleks kasutusele URL muutuja ning määra tootele.
- Tee uus API otspunkt, mis käivitades muudab toote hinda muutujana antud numbri kordseks. Võta selleks kasutusele URL muutuja ning korruta toote hinnaga läbi.
// harjutused
//1
[HttpGet("muuda_staatus")]
public Toode MuudaStaatus()
{
if (_toode.IsActive == true) {
_toode.IsActive = false;
}
else
{
_toode.IsActive = true;
}
return _toode;
}
//2
[HttpGet("muuda-nimi/{newName}")]
public IActionResult MuudaNimi(string newName)
{ _toode.Name = newName;
return Ok(_toode);
}
//3
[HttpGet("muuda-hind/{kordaja}")]
public IActionResult MuudaHind(double kordaja)
{
_toode.Price = _toode.Price * kordaja;
return Ok(_toode);
}
API päringud mudeli ja listiga
Lisame Tooted Controller:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[ApiController]
[Route("[controller]")]
public class TootedController : ControllerBase
{
private static List<Toode> _tooted = new List<Toode>{
new Toode(1,"Koola", 1.5, true),
new Toode(2,"Fanta", 1.0, false),
new Toode(3,"Sprite", 1.7, true),
new Toode(4,"Vichy", 2.0, true),
new Toode(5,"Vitamin well", 2.5, true)
};
// https://localhost:4444/tooted
[HttpGet]
public List<Toode> Get()
{
return _tooted;
}
[HttpGet("kustuta/{index}")]
public List<Toode> Delete(int index)
{
_tooted.RemoveAt(index);
return _tooted;
}
[HttpGet("kustuta2/{index}")]
public string Delete2(int index)
{
_tooted.RemoveAt(index);
return "Kustutatud!";
}
[HttpGet("lisa/{id}/{nimi}/{hind}/{aktiivne}")]
public List<Toode> Add(int id, string nimi, double hind, bool aktiivne)
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
return _tooted;
}
[HttpGet("lisa")] // GET /tooted/lisa?id=1&nimi=Koola&hind=1.5&aktiivne=true
public List<Toode> Add2([FromQuery] int id, [FromQuery] string nimi, [FromQuery] double hind, [FromQuery] bool aktiivne)
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
return _tooted;
}
[HttpGet("hind-dollaritesse/{kurss}")] // GET /tooted/hind-dollaritesse/1.5
public List<Toode> Dollaritesse(double kurss)
{
for (int i = 0; i < _tooted.Count; i++)
{
_tooted[i].Price = _tooted[i].Price * kurss;
}
return _tooted;
}
// või foreachina:
[HttpGet("hind-dollaritesse2/{kurss}")] // GET /tooted/hind-dollaritesse2/1.5
public List<Toode> Dollaritesse2(double kurss)
{
foreach (var t in _tooted)
{
t.Price = t.Price * kurss;
}
return _tooted;
}
}
}
Harjutused:
- Tee uus API otspunkt, mis kustutab korraga kõik tooted.
- Tee uus API otspunkt, mis muudab kõikide toodete aktiivsuse väära peale.
- Tee uus API otspunkt, mis tagastab ühe toote – vastavalt kelle järjekorranumber on lisatud URL muutujasse.
- Tee uus API otspunkt, mis tagastab ühe toote – kõige suurema hinnaga toote.
//1
[HttpGet("kustuta_koik")]
public string KutstutaKoik()
{
for (int i = 0; i < _tooted.Count; i++)
{
_tooted.RemoveAt(i);
}
return "Kustutatud kõik tooted!";
}
//2
[HttpGet("keela_koik")]
public string KeelaKoik()
{
for (int i = 0; i < _tooted.Count; i++)
{
_tooted[i].IsActive=false;
}
return "Keelatud kõik tooted!";
}
//3
[HttpGet("otsi")] // GET /tooted/otsi?id=1
public Toode Otsi([FromQuery] int id)
{
return _tooted[id-1];
}
//4
[HttpGet("koige_kallis")]
public IActionResult OtsiKoigeKallis()
{
if (_tooted == null || !_tooted.Any())
{
return NotFound("Toodete nimekiri on tühi.");
}
var koigeKallim = _tooted.OrderByDescending(t => t.Price).FirstOrDefault();
return Ok(koigeKallim);
}
Eesliidese implementeerimine
Teeme eesrakenduse Reactiga.
npx create-react-app frontend
cd frontend
npm start
Tulemus:

Lisame kood frontendis App.js
import { useEffect, useRef, useState } from 'react';
import './App.css';
function App() {
const [tooted, setTooted] = useState([]);
const idRef = useRef();
const nameRef = useRef();
const priceRef = useRef();
const isActiveRef = useRef();
const [isUsd, setUsd] = useState(false);
useEffect(() => {
fetch("https://localhost:4444/tooted")
.then(res => res.json())
.then(json => setTooted(json));
}, []);
function kustuta(index) {
fetch("https://localhost:4444/tooted/kustuta/" + index)
.then(res => res.json())
.then(json => setTooted(json));
}
function lisa() {
fetch(`https://localhost:4444/tooted/lisa/${Number(idRef.current.value)}/${nameRef.current.value}/${Number(priceRef.current.value)}/${isActiveRef.current.checked}`)
.then(res => res.json())
.then(json => setTooted(json));
}
function dollariteks() {
const kurss = 1.1;
setUsd(true);
fetch("https://localhost:4444/tooted/hind-dollaritesse/" + kurss)
.then(res => res.json())
.then(json => setTooted(json));
}
function eurodeks() {
const kurss = 0.9091;
setUsd(false);
fetch("https://localhost:4444/tooted/hind-dollaritesse/" + kurss)
.then(res => res.json())
.then(json => setTooted(json));
}
return (
<div className="App">
<label>ID</label> <br />
<input ref={idRef} type="number" /> <br />
<label>name</label> <br />
<input ref={nameRef} type="text" /> <br />
<label>price</label> <br />
<input ref={priceRef} type="number" /> <br />
<label>isActive</label> <br />
<input ref={isActiveRef} type="checkbox" /> <br />
<button onClick={() => lisa()}>Lisa</button>
{tooted.map((toode, index) =>
<div>
<div>{toode.id}</div>
<div>{toode.name}</div>
<div>{toode.price.toFixed(2)}</div>
<button onClick={() => kustuta(index)}>x</button>
</div>)}
{isUsd === false && <button onClick={() => dollariteks()}>Muuda dollariteks</button>}
{isUsd === true && <button onClick={() => eurodeks()}>Muuda eurodeks</button>}
</div>
);
}
export default App;
Parimad praktikad
Lisame järgmised read Program.cs faili võõra rakenduse meie tagarakendusele ligi lubamiseks
Tahame, et meie tagarakenduse koodile pääseme vaid meie oma eesrakendusega ligi. Piirame seda ainult meie pordile.
app.UseCors(options => options
.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader()
);
Paneme GET päringute asemel lisaks PUT, POST, PATCH, DELETE
Tähendused:
- GET – andmete võtmiseks
- PUT – andmete asendamiseks
- POST – andmete lisamiseks
- PATCH – ühe omaduse muutmiseks
- DELETE – kustutamiseks
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[ApiController]
[Route("[controller]")]
public class TootedController : ControllerBase
{
private static List<Toode> _tooted = new List<Toode>{
new Toode(1,"Koola", 1.5, true),
new Toode(2,"Fanta", 1.0, false),
new Toode(3,"Sprite", 1.7, true),
new Toode(4,"Vichy", 2.0, true),
new Toode(5,"Vitamin well", 2.5, true)
};
// GET https://localhost:4444/tooted
[HttpGet]
public List<Toode> Get()
{
return _tooted;
}
// DELETE https://localhost:4444/tooted/kustuta/0
[HttpDelete("kustuta/{index}")]
public List<Toode> Delete(int index)
{
_tooted.RemoveAt(index);
return _tooted;
}
[HttpDelete("kustuta2/{index}")]
public string Delete2(int index)
{
_tooted.RemoveAt(index);
return "Kustutatud!";
}
// POST https://localhost:4444/tooted/lisa/1/Coca/1.5/true
[HttpPost("lisa/{id}/{nimi}/{hind}/{aktiivne}")]
public List<Toode> Add(int id, string nimi, double hind, bool aktiivne)
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
return _tooted;
}
[HttpPost("lisa2")]
public List<Toode> Add2(int id, string nimi, double hind, bool aktiivne)
{
Toode toode = new Toode(id, nimi, hind, aktiivne);
_tooted.Add(toode);
return _tooted;
}
// PATCH https://localhost:4444/tooted/hind-dollaritesse/1.5
[HttpPatch("hind-dollaritesse/{kurss}")]
public List<Toode> UpdatePrices(double kurss)
{
for (int i = 0; i < _tooted.Count; i++)
{
_tooted[i].Price = _tooted[i].Price * kurss;
}
return _tooted;
}
// või foreachina:
[HttpPatch("hind-dollaritesse2/{kurss}")] // GET /tooted/hind-dollaritesse2/1.5
public List<Toode> Dollaritesse2(double kurss)
{
foreach (var t in _tooted)
{
t.Price = t.Price * kurss;
}
return _tooted;
}
// harjutused
//1
[HttpDelete("kustuta-koik")]
public IActionResult KustutaKoik()
{
_tooted.Clear();
return Ok("Kõik tooted on kustutatud!");
}
//2
[HttpPatch("keela-koik")]
public IActionResult KeelaKoik()
{
foreach (var t in _tooted)
{
t.IsActive = false;
}
return Ok("Kõik tooted on keelatud!");
}
//3
[HttpGet("otsi")]
public ActionResult<Toode> Otsi([FromQuery] int id)
{
if (id < 1 || id > _tooted.Count)
{
return NotFound("Toodet ei leitud!");
}
return Ok(_tooted[id - 1]);
}
//4
[HttpGet("koige-kallis")]
public IActionResult OtsiKoigeKallis()
{
if (_tooted == null || !_tooted.Any())
{
return NotFound("Toodete nimekiri on tühi.");
}
var koigeKallim = _tooted.OrderByDescending(t => t.Price).FirstOrDefault();
return Ok(koigeKallim);
}
}
}
Peame muutma ka eesrakenduses kõik tüübid korrektseks nagu tagarakenduses, muidu enam ühendus ei toimi
function kustuta(index) { ////////////////////////
fetch("https://localhost:4444/tooted/kustuta/" + index, {"method": "DELETE"})
.then(res => res.json())
.then(json => setTooted(json));
}
function lisa() { ////////////////////////
fetch(`https://localhost:4444/tooted/lisa/
${Number(idRef.current.value)}/${nameRef.current.value}/
${Number(priceRef.current.value)}/${isActiveRef.current.checked}`, {"method": "POST"})
.then(res => res.json())
.then(json => setTooted(json));
}
function dollariteks() {
const kurss = 1.1; ////////////////////////
fetch("https://localhost:4444/tooted/hind-dollaritesse/" + kurss, {"method": "PATCH"})
.then(res => res.json())
.then(json => setTooted(json));
}
function eurodeks() {
const kurss = 0.9091;
setUsd(false);
fetch("https://localhost:4444/tooted/hind-dollaritesse/" + kurss, {"method": "PATCH"})
.then(res => res.json())
.then(json => setTooted(json));
}
Kui võtame vastu suure hulga muutujaid läbi URLi, võiksime sellest teha andmemudeli. Kohustuslik on see siis, kui me võtamegi URLi muutujate abil ükshaaval andmemudeli vastu (praegusel juhul võtame Toote).
[HttpPost("lisa")]
public List<Toode> Add([FromBody] Toode toode)
{
_tooted.Add(toode);
return _tooted;
}
Front:
////////////////////////
function lisa() {
const uusToode = {
"id": Number(idRef.current.value),
"name": nameRef.current.value,
"price": Number(priceRef.current.value),
"isActive": isActiveRef.current.checked
}
fetch("https://localhost:4444/tooted/lisa", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(uusToode)
})
.then(res => res.json())
.then(json => setTooted(json));
}
////////////////////////
Kontroll:
Postmanis tuleb body kaasa saates kasutada API otspunktina http://localhost:4444/tooted/lisa ja vajutada “body” -> “raw” -> “json” ning sisestada päringu keha järgneval kujul:
{
"id": 321,
"name": "Red bull",
"price": 5,
"isActive": true
}

Iseseisev harjutus:
- Tee tagarakendusse uus API otspunkt, mis muudab toodet. Kasuta PUT päringu tüüpi. Eesrakenduses pole midagi lisada vaja.
[HttpPut("uuenda")]
public IActionResult Uuenda([FromBody] Toode uuendatudToode)
{
var olemas = _tooted.FirstOrDefault(t => t.Id == uuendatudToode.Id);
if (olemas == null)
{
return NotFound("Toodet ei leitud!");
}
olemas.Name = uuendatudToode.Name;
olemas.Price = uuendatudToode.Price;
olemas.IsActive = uuendatudToode.IsActive;
return Ok(olemas);
}
Testin uus endpoint: http://localhost:4444/tooted/uuenda

API päring teise rakendusse: pakiautomaatide kättesaamine
Lisa järgnev lõik Program.cs faili, mis võimaldab rakendusega HttpClient võimalused siduda.
builder.Services.AddHttpClient();
Loome uue kontroller ParcelMachineController HTTP klientiga.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class ParcelMachineController : ControllerBase
{
private readonly HttpClient _httpClient;
public ParcelMachineController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet]
public async Task<IActionResult> GetParcelMachines()
{
var response = await _httpClient.GetAsync("https://www.omniva.ee/locations.json");
var responseBody = await response.Content.ReadAsStringAsync();
return Content(responseBody, "application/json");
}
}
}
Muudatud frontendi kood:
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [pakiautomaadid, setPakiautomaadid] = useState([]);
// Saame Omniva postiautomaadid
useEffect(() => {
fetch("https://localhost:4444/ParcelMachine")
.then(res => res.json())
.then(json => setPakiautomaadid(json));
}, []);
return (
<div className="App">
<select>
{pakiautomaadid.map(automaat =>
<option>
{automaat.NAME}
</option>)}
</select>
</div>
);
}
export default App;
Tulemus:

Iseseisev harjutus:
- Võta kõik pakiautomaadid eraldi API otspunktis ka SmartPost lehelt: https://my.smartpost.ee/api/ext/v1/places?country=EE
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class SmartPostController : ControllerBase
{
private readonly HttpClient _httpClient;
public SmartPostController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet]
public async Task<IActionResult> GetSmartPost()
{
var request = new HttpRequestMessage(HttpMethod.Get, "https://my.smartpost.ee/api/ext/v1/places?country=EE");
// Mõned API-d nõuavad User-Agenti päist
request.Headers.Add("User-Agent", "SmartPostClient/1.0");
// Saadame päringu
var response = await _httpClient.SendAsync(request);
// Saame vastuse stringina (XML-vormingus)
var xmlString = await response.Content.ReadAsStringAsync();
// Laadime XML-stringi XDocumenti, et struktuuri oleks mugavam analüüsida.
var xdoc = XDocument.Parse(xmlString);
var places = xdoc.Descendants("item").Select(x => new {
PlaceId = (string?)x.Element("place_id"),
Name = (string?)x.Element("name"),
Address = (string?)x.Element("address"),
City = (string?)x.Element("city"),
PostalCode = (string?)x.Element("postalcode"),
Type = (string?)x.Element("type"),
Lat = (double?)x.Element("lat"),
Lng = (double?)x.Element("lng"),
Availability = (string?)x.Element("availability")
});
return Ok(places);
}
}
}

App.js
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [omnivaMachines, setOmnivaMachines] = useState([]);
const [smartPostMachines, setSmartPostMachines] = useState([]);
useEffect(() => {
// Saame SmartPosti postiautomaadid
fetch("https://localhost:4444/smartpost")
.then(res => res.json())
.then(json => setSmartPostMachines(json));
}, []);
return (
<div className="App">
<h2>SmartPost pakiautomaadid</h2>
<select>
{smartPostMachines.map(automaat =>
<option key={automaat.ID || automaat.name || automaat.NAME}>
{automaat.NAME || automaat.name}
</option>
)}
</select>
</div>
);
}
export default App;
Tulemus:

API päring teise rakendusse: Elering hindade kättesaamine
Loome uue kontroller NordpoolController
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("api/[controller]")]// Marsruutimise atribuut: aadress algab api/Nordpool
[ApiController] // Näitab, et tegemist on API kontrolleriga
public class NordpoolController : ControllerBase
{
// HttpClient'i salvestamiseks mõeldud privaatne väli, mida kasutatakse HTTP-päringute täitmiseks
private readonly HttpClient _httpClient;
// Kontrollerikonstruktor, milles edastatakse HttpClient'i eksemplar
public NordpoolController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet]
public async Task<IActionResult> GetNordpoolPrices()
{
// Saadame asünkroonselt GET-päringu välisele Nord Pooli API-le
var response = await _httpClient.GetAsync("https://dashboard.elering.ee/api/nps/price");
// Saame vastuse sisu stringina
var responseBody = await response.Content.ReadAsStringAsync();
// Tagastame saadud andmed JSON-vormingus
return Content(responseBody, "application/json");
}
}
}

App.js
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [fi, setFi] = useState([]);
const [ee, setEe] = useState([]);
const [lv, setLv] = useState([]);
const [lt, setLt] = useState([]);
useEffect(() => {
fetch("https://localhost:4444/nordpool")
.then(res => res.json())
.then(json => {
setFi(json.data.fi);
setEe(json.data.ee)
setLv(json.data.lv)
setLt(json.data.lt)
});
}, []);
return (
<div>
<table style={{marginLeft: "100px"}}>
<thead>
<th style={{border: "1px solid #ddd", padding: "12px", backgroundColor: "#04AA6D"}}>Ajatempel</th>
<th style={{border: "1px solid #ddd", padding: "12px", backgroundColor: "#04AA6D"}}>Hind</th>
</thead>
<tbody>
<div style={{position: "absolute", left: "30px"}}>Soome</div>
{fi.map(data =>
<tr key={data.timestamp}>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{new Date(data.timestamp * 1000).toISOString()}</td>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{data.price}</td>
</tr>)}
<div style={{position: "absolute", left: "30px"}}>Eesti</div>
{ee.map(data =>
<tr key={data.timestamp}>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{new Date(data.timestamp * 1000).toISOString()}</td>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{data.price}</td>
</tr>)}
<div style={{position: "absolute", left: "30px"}}>Läti</div>
{lv.map(data =>
<tr key={data.timestamp}>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{new Date(data.timestamp * 1000).toISOString()}</td>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{data.price}</td>
</tr>)}
<div style={{position: "absolute", left: "30px"}}>Leedu</div>
{lt.map(data =>
<tr key={data.timestamp}>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{new Date(data.timestamp * 1000).toISOString()}</td>
<td style={{border: "1px solid #ddd", padding: "8px"}}>{data.price}</td>
</tr>)}
</tbody>
</table>
</div>
);
}
export default App;
Tulemus:

API päring teise rakendusse: Elering päringu modifitseerimine
Eesrakendus soovib API otspunkti konfigureerida selliseks, et saadetakse kaasa “ee”, “lv”, “lt” või “fi” parameeter ning näidatakse selle riigi hindasid. Teeme.
Eesrakendus näitab kuupäevasid peale vajutades näidatakse selle kuupäeva hindasid. Meie ülesanne on eesrakendusel seda võimaldada, võttes eesrakendusest vastu kuupäeva ning saate selle Elering API otspunktile
Loome NordpoolController
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]// Marsruutimise atribuut: aadress algab api/Nordpool
[ApiController] // Näitab, et tegemist on API kontrolleriga
public class NordpoolController : ControllerBase
{
// HttpClient'i salvestamiseks mõeldud privaatne väli, mida kasutatakse HTTP-päringute täitmiseks
private readonly HttpClient _httpClient;
// Kontrollerikonstruktor, milles edastatakse HttpClient'i eksemplar
public NordpoolController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("{country}/{start}/{end}")]
public async Task<IActionResult> GetNordPoolPrices(
string country, // riigi kood (ee, lv, lt, fi)
string start, // perioodi alguskuupäev
string end) // perioodi lõppkuupäev
{
var response = await _httpClient.GetAsync($"https://dashboard.elering.ee/api/nps/price?start={start}&end={end}");
var responseBody = await response.Content.ReadAsStringAsync();
var jsonDoc = JsonDocument.Parse(responseBody);
var dataProperty = jsonDoc.RootElement.GetProperty("data");
JsonElement prices;
switch (country)
{
case "ee":
prices = dataProperty.GetProperty("ee");
break;
case "lv":
prices = dataProperty.GetProperty("lv");
break;
case "lt":
prices = dataProperty.GetProperty("lt");
break;
case "fi":
prices = dataProperty.GetProperty("fi");
break;
default:
return BadRequest("Invalid country code.");
}
return new JsonResult(prices);
}
}
}
Testime backendi:


Muudatud App.js
import { useRef } from 'react';
import { useEffect, useState } from 'react';
import './App.css';
function App() {
const [prices, setPrices] = useState([]);
const [chosenCountry, setChosenCountry] = useState("ee");
const [start, setStart] = useState("");
const [end, setEnd] = useState("");
const startRef = useRef();
const endRef = useRef();
useEffect(() => {
if (start !== "" && end !== "") {
fetch("https://localhost:4444/nordpool/" + chosenCountry + "/" + start + "/" + end)
.then(res => res.json())
.then(json => {
setPrices(json);
});
}
}, [chosenCountry, start, end]);
function updateStart() {
const startIso = new Date(startRef.current.value).toISOString();
setStart(startIso);
}
function updateEnd() {
const endIso = new Date(endRef.current.value).toISOString();
setEnd(endIso);
}
return (
<div>
<button onClick={() => setChosenCountry("fi")}>Soome</button>
<button onClick={() => setChosenCountry("ee")}>Eesti</button>
<button onClick={() => setChosenCountry("lv")}>Läti</button>
<button onClick={() => setChosenCountry("lt")}>Leedu</button>
<input ref={startRef} onChange={updateStart} type="datetime-local" />
<input ref={endRef} onChange={updateEnd} type="datetime-local" />
{prices.length > 0 &&
<table style={{marginLeft: "100px"}}>
<thead>
<tr>
<th>Riik</th>
<th>Ajatempel</th>
<th>Hind</th>
</tr>
</thead>
<tbody>
{prices.map(data =>
<tr key={data.timestamp}>
<td>{chosenCountry}</td>
<td>{new Date(data.timestamp * 1000).toLocaleString()}</td>
<td>{data.price.toFixed(2)}</td>
</tr>)}
</tbody>
</table>}
</div>
);
}
export default App;
Kontroll:

API päring teise rakendusse: Makse
Makse teostamiseks on vajalik järgmine kood:
namespace Veebirakenduse_Koostamine.Controllers
{
[Route("[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly HttpClient _httpClient;
public PaymentController(HttpClient httpClient)
{
_httpClient = httpClient;
}
[HttpGet("{sum}")]
public async Task<IActionResult> MakePayment(string sum)
{
var paymentData = new
{
api_username = "e36eb40f5ec87fa2",
account_name = "EUR3D1",
amount = sum,
order_reference = Math.Ceiling(new Random().NextDouble() * 999999),
nonce = $"a9b7f7e7as{DateTime.Now}{new Random().NextDouble() * 999999}",
timestamp = DateTime.Now,
customer_url = "https://maksmine.web.app/makse"
};
var json = JsonSerializer.Serialize(paymentData);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "ZTM2ZWI0MGY1ZWM4N2ZhMjo3YjkxYTNiOWUxYjc0NTI0YzJlOWZjMjgyZjhhYzhjZA==");
var response = await client.PostAsync("https://igw-demo.every-pay.com/api/v4/payments/oneoff", content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var jsonDoc = JsonDocument.Parse(responseContent);
var paymentLink = jsonDoc.RootElement.GetProperty("payment_link");
return Ok(paymentLink);
}
else
{
return BadRequest("Payment failed.");
}
}
}
}
Kontrollime


Selgitused/tähelepanekud:
Summa asemel võiks tegelikult eesrakendus saata toodete nimistu, millelt tagarakendus ise kogusumma arvutab.
API username on turvaelement, mis peab ühtima sellega, mis on kasutaja poolt Authorization headerisse lisatud.
Account name tähistab, millisele kontole makse laekub. Kliendil võib olla erinevaid kontosid.
Amount on summa, millega maksesse sisenetakse.
Order_reference on tellimuse number.
Nonce on turvaelement, mis peab olema absoluutselt iga päring unikaalne.
Timestamp on makse algatamise kuupäev.
Customer_url on väärtus, kuhu kasutaja pärast makse sooritamist suunatakse.
Headeritesse on kirjutatud Authorization võtme alla Basic Auth abil kasutajanimi ja parool.
Content-Type abil on antud teada, et EveryPay suunas liigub JSON kuju.
Eesrakendusele tagastatakse return Ok() sees EveryPay poolt saadetud makselink (payment_link).
Antud API otspunkti eesmärk ongi genereerida EveryPay link, mis on vaja eesrakendusele anda ning mis suunab kasutaja täpselt selle lingile.
Järgneb makse, mis on testkonnas läbi viidud nii nagu allpool kirjas: