Veebirakenduste loomine API päringute abil

Loomine projekt:

Muuda controllers:

using Microsoft.AspNetCore.Mvc;
 
namespace veeb.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
 
        private readonly ILogger<WeatherController> _logger;
 
        public WeatherController(ILogger<WeatherController> logger)
        {
            _logger = logger;
        }
 
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

Töö kontroll:

Esialgsete API taotluste tegemine

Lisa uus fail “PrimitiividController”:

using Microsoft.AspNetCore.Mvc;

namespace veebb.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);
            }
        }
    }
}

Lisa uus kaust(Models) ja fail(Toode)

Loo uus kood:

Loomine Models:

Lisa uude klass järgnev kood:

namespace veebb.models;
 
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

Uue kontrolleri lisamine:

using Microsoft.AspNetCore.Mvc;
using veebb.models;

namespace veebb.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;
        }
    }
}

Kontrollida:

API-päringud mudeli ja loendiga

Uue kontrolleri lisamine:

Kood:

using Microsoft.AspNetCore.Mvc;
using veebb.models;

namespace veebb.Controllers;

[ApiController]
[Route("[controller]")]
public class TootedController
{
    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:7052/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;
    }
}

Terminali kasutamise alustamine

App.js

import { useEffect, useRef, useState } from 'react';
import './App.css';

function App() {
  const [tooted, setTooted] = useState([]);

  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));
  }

  return (
    <div className="App">
      {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>)}
    </div>
  );
}

export default App;

Kohaliku hosti numbrite muutmine:

Lisage faili Program.cs järgmised:

var builder = WebApplication.CreateBuilder(args);
 
// Add services to the container.
 
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
 
var app = builder.Build();
 
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
 
app.UseHttpsRedirection();
 
app.UseCors(options => options
    .WithOrigins("*")
    .AllowAnyMethod()
    .AllowAnyHeader()
);
 
app.UseAuthorization();
 
app.MapControllers();
 
app.Run();

Lisa app.js faili järgmine sisu:

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

Kogu fail (Program.cs) näeb välja selline:

var builder = WebApplication.CreateBuilder(args);
 
// Add services to the container.
 
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
 
var app = builder.Build();
 
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
 
app.UseHttpsRedirection();
 
app.UseCors(options => options
    .WithOrigins("http://localhost:3000")
    .AllowAnyMethod()
    .AllowAnyHeader()
);
 
app.UseAuthorization();
 
app.MapControllers();
 
app.Run();

TootedControler.cs

using Microsoft.AspNetCore.Mvc;
using veeb.models;
 
namespace veeb.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class TootedController : ControllerBase
    {
        private static List<Toode> _tooted = new()
        {
            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;
        }
    }
}

Samuti peame rakendusele (tervikuna) tegema õige täienduse, vastasel juhul ühendus enam ei tööta (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();
 
 
  useEffect(() => {
    fetch("https://localhost:4444/tooted")
      .then(res => res.json())
      .then(json => setTooted(json));
  }, []);
 
  function kustuta(index) {
    fetch("https://localhost:4444/tooted/kustuta/" + index, {"method": "DELETE"})
      .then(res => res.json())
      .then(json => setTooted(json));
  }
 
  ////////////////////////
  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", "body": JSON.stringify(uusToode)})
      .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));
  }
 
  return (
    <div className="App">
      <label>ID</label> <br />
      <input ref={idRef} type="number" /> <br />
      <label>Nimi</label> <br />
      <input ref={nameRef} type="text" /> <br />
      <label>Hind</label> <br />
      <input ref={priceRef} type="number" /> <br />
      <label>Aktiivne</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}</div>
          <button onClick={() => kustuta(index)}>x</button>
        </div>)}
      <button onClick={() => dollariteks()}>Muuda dollariteks</button>
    </div>
  );
}
 
export default App;

Näitav:

API päring teisele rakendusele: paki vastuvõtmine pakiautomaadist

Uue kontrolleri lisamine:

Käivituskood:

using Microsoft.AspNetCore.Mvc;
 
namespace veeb.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class ParcelMachineController : ControllerBase
    {
         
    }
}

Teine punkt:

using Microsoft.AspNetCore.Mvc;
 
namespace veeb.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class ParcelMachineController : ControllerBase
    {
         
        [HttpGet]
        public string GetParcelMachines()
        {
            return "PAKIAUTOMAADID";
        }
    }
}

Kolmas punkt:

using Microsoft.AspNetCore.Mvc;

namespace veeb.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class ParcelMachineController : ControllerBase
    {
        private readonly HttpClient _httpClient;

        public ParcelMachineController(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
        
        [HttpGet]
        public async Task<string> GetParcelMachines()
        {
            var response = await _httpClient.GetAsync("https://www.omniva.ee/locations.json");
            var responseBody = await response.Content.ReadAsStringAsync();
            return "PAKIAUTOMAADID";
        }
    }
}

Neljas punkt:

using Microsoft.AspNetCore.Mvc;

namespace veeb.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");
        }
    }
}

Näita pakiautomaate Reactis:

import { useEffect, useState } from 'react';
import './App.css';

function App() {
  const [pakiautomaadid, setPakiautomaadid] = useState([]);

  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;

Näide:

API päring teise rakendusse: Elering hindade kättesaamine

Uue kontrolleri lisamine:

using Microsoft.AspNetCore.Mvc;
 
namespace veeb.Controllers
{
    [Route("[controller]")]
[ApiController]
public class NordpoolController : ControllerBase
{
    private readonly HttpClient _httpClient;
 
    public NordpoolController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
 
    [HttpGet]
    public async Task<IActionResult> GetNordpoolPrices()
    {
        var response = await _httpClient.GetAsync("https://dashboard.elering.ee/api/nps/price");
        var responseBody = await response.Content.ReadAsStringAsync();
        return Content(responseBody, "application/json");
    }
}
}

API päring teise rakendusse: Elering päringu modifitseerimine

Rakenduse esikülg näeb välja selline:

import { useEffect, useState } from 'react';
import './App.css';
 
function App() {
  const [prices, setPrices] = useState([]);
  const [chosenCountry, setChosenCountry] = useState("ee");
 
  useEffect(() => {
    fetch("https://localhost:4444/nordpool/" + chosenCountry)
      .then(res => res.json())
      .then(json => {
        setPrices(json);
      });
  }, [chosenCountry]);
 
  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>
      <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"}}>{chosenCountry}</div>
          {prices.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;

Seega peame looma taustarakenduse, mis aktsepteerib parameetrit:

using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
 
namespace veeb.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class NordpoolController : ControllerBase
    {
 
        private readonly HttpClient _httpClient;
 
        public NordpoolController(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
 
        [HttpGet("{country}")]
        public async Task<IActionResult> GetNordPoolPrices(string country)
        {
            var response = await _httpClient.GetAsync("https://dashboard.elering.ee/api/nps/price");
            var responseBody = await response.Content.ReadAsStringAsync();
            var jsonDoc = JsonDocument.Parse(responseBody);
            var dataProperty = jsonDoc.RootElement.GetProperty("data");
 
            string prices;
 
            switch (country)
            {
                case "ee":
                    prices = dataProperty.GetProperty("ee").ToString();
                    return Content(prices, "application/json");
 
                case "lv":
                    prices = dataProperty.GetProperty("lv").ToString();
                    return Content(prices, "application/json");
 
                case "lt":
                    prices = dataProperty.GetProperty("lt").ToString();
                    return Content(prices, "application/json");
 
                case "fi":
                    prices = dataProperty.GetProperty("fi").ToString();
                    return Content(prices, "application/json");
 
                default:
                    return BadRequest("Invalid country code.");
            }
        }
    }
}

Näide:

Kliendipoolne rakendus kuvab kuupäevi, millele klõpsamisel kuvatakse selle kuupäeva hinnad. Meie eesmärk on, et kliendipoolne rakendus toetaks seda funktsiooni, võttes kliendipoolselt rakenduselt vastu andmeid ja saates need Elering API lõpp-punkti.

API päring teise rakendusse: Makse

Uue kontrolleri loomine:

Kood:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
 
namespace VeebTARpv23.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.");
            }
        }
    }
}

Näide:

Läheme Postman sisse ja teeme GET päring

Oma link: https://payment.sandbox.lhv.ee/lp/7m7jmbz3hj/DNzmFVyMzD

Võtame ükskõik millise panga, mina võtan LHV:

Näeme, et seal on liivakast, võtame selle:

Võtame suvalise kasutaja, valin Smart-ID ja seejärel klõpsan lihtsalt nuppu “Kinnita”:

Ootame kuni ta töötleb selle tulemuse:

Tulemuseks me saame:

Postman