Рубрики
Без рубрики

Узел и React Router Динамические API Маршруты API

Мы будем создавать веб-сайт библиотеки книги, похожий на звуковую API, у которого есть API узла Backend. Это API W … Tagged JavaScript, WebDev, Учебник, Реагируйте.

Мы будем создавать веб-сайт библиотеки книги, похожий на звуковую API, у которого есть API узла Backend. Эта API проведет данные книги, которые будут динамически доступны, позволяя вам выбрать все книги, а также книги по идентификатору книги. Вы узнаете, как создавать маршруты на бэкэнде, а также на интерфейсе в реакцию, используя React Router.

Шаг 1: Настройка проекта Backend

Создайте папку для вашего проекта, а затем CD внутрь. Скопируйте и вставьте этот код в свой терминал, а затем нажмите Enter, чтобы настроить ваш проект

touch .gitignore  
mkdir backend
cd backend
touch .gitignore
npm init -y
npm i express nodemon cors concurrently uuid
mkdir controllers data models public routes
touch app.js
touch controllers/admin.js
touch routes/admin.js
touch models/Books.js
touch data/books.json

CD в корневую папку, а затем откройте проект в вашем редакторе кода. Добавьте код ниже на обоих .gitignore файлы

.DS_STORE
node_modules

Скопируйте и вставьте код ниже в соответствующие файлы

app.js.

const express = require('express');
const cors = require('cors');
const adminRoute = require('./routes/admin');

const app = express();
app.use(cors());

app.use(express.urlencoded({ extended: false }));

app.use('/', adminRoute);

const port = process.env.PORT || 8080;

app.listen(port, () => console.log(`Server running on port ${port}, http://localhost:${port}`));

Контроллеры/admin.js.

exports.getIndex = (req, res) => {
    res.send('Book Library Home Route');
};

Маршруты/admin.js.

const express = require('express');
const router = express.Router();
const adminController = require('../controllers/admin');

router.get('/', adminController.getIndex);

module.exports = router;

Добавьте эти сценарии запуска на ваш package.json файл

"scripts": {
        "start": "node app.js",
        "dev": "nodemon app.js",
        "servers": "concurrently \"npm run start\" \"cd ../frontend && npm run start\""
    },

Теперь запустите команду NPM запустить Dev Из вашей папки Backend и сервер должен быть запущен и работает.

Шаг 2: Создайте остальные API

В этом руководстве мы будем использовать локальный файловый сервер, однако это довольно просто подключить его к базе данных. Если вы хотите узнать, как подключить базу данных MongoDB, вы можете прочитать мою статью, создавая приложения для стека MERN (2020)

Заменить и обновить код в существующие файлы с теми ниже

Контроллеры/admin.js.

const Books = require('../models/Books');

exports.getIndex = (req, res) => {
    res.send('Book Library Home Route');
};

exports.getBooks = (req, res) => {
    Books.fetchAll((books) => {
        console.log(books);
        res.json(books);
    });
};

exports.getBook = (req, res) => {
    const bookId = req.params.bookId;

    Books.findById(bookId, (book) => {
        console.log(book);
        res.json(book);
    });
};

exports.postAddBook = (req, res) => {
    const { name, author, narrated, img, bookLength, releaseDate, language } = req.body;

    const book = new Books(null, name, author, narrated, img, bookLength, releaseDate, language);
    book.save();
    res.json({ msg: 'Book Added' });
};

Данные/Книги.json.

[
    {
        "id": "647f8d9a-97b5-461c-9cfe-b04d8b9e1028",
        "name": "Algorithms to Live By The Computer Science of Human Decisions",
        "author": "Brian Christian, Tom Griffiths",
        "narrated": "Brian Christian",
        "img": "https://m.media-amazon.com/images/I/519lKuoLN-L._SL500_.jpg",
        "bookLength": "11 hrs and 50 mins",
        "releaseDate": "19-04-16",
        "language": "English"
    },
    {
        "id": "acf5dcd6-0b8f-4838-9951-3dd1e0f88aee",
        "name": "Psycho-Cybernetics Updated and Expanded",
        "author": "Maxwell Maltz",
        "narrated": "Matt Furey",
        "img": "https://m.media-amazon.com/images/I/51XVTl7HZTL._SL500_.jpg",
        "bookLength": "12 hrs and 16 mins",
        "releaseDate": "11-04-17",
        "language": "English"
    },
    {
        "id": "edc89cce-c823-4690-afc3-d6aa7c8a3be9",
        "name": "A Survival Guide for Life",
        "author": "Bear Grylls",
        "narrated": "Tom Patrick Stephens",
        "img": "https://m.media-amazon.com/images/I/51pNAYZrptL._SL500_.jpg",
        "bookLength": "3 hrs and 32 mins",
        "releaseDate": "26-09-13",
        "language": "English"
    },
    {
        "id": "f19b22bb-c4b4-42a4-be32-4bffa6a89fac",
        "name": "Never Split the Difference Negotiating as if Your Life Depended on It",
        "author": "Chris Voss, Tahl Raz",
        "narrated": "Michael Kramer",
        "img": "https://m.media-amazon.com/images/I/51TSWCruAHL._SL500_.jpg",
        "bookLength": "8 hrs and 7 mins",
        "releaseDate": "20-06-19",
        "language": "English"
    },
    {
        "id": "94cb2436-2bdf-4872-bfd8-9acb860f5a0d",
        "name": "A Life in Parts",
        "author": "Bryan Cranston",
        "narrated": "Bryan Cranston",
        "img": "https://m.media-amazon.com/images/I/51nBvxV-3+L._SL500_.jpg",
        "bookLength": "8 hrs and 51 mins",
        "releaseDate": "20-10-16",
        "language": "English"
    },
    {
        "id": "e18926e7-494e-4604-82c5-daeb4ea1dde9",
        "name": "Elon Musk",
        "author": "Ashlee Vance",
        "narrated": "Fred Sanders",
        "img": "https://m.media-amazon.com/images/I/51e-uVPtr5L._SL500_.jpg",
        "bookLength": "13 hrs and 23 mins",
        "releaseDate": "28-04-16",
        "language": "English"
    },
    {
        "id": "f69fa7bb-93f6-497f-8e99-108467af8124",
        "name": "Steve Jobs The Exclusive Biography",
        "author": "Walter Isaacson",
        "narrated": "Dylan Baker, Walter Isaacson (introduction)",
        "img": "https://m.media-amazon.com/images/I/51b8AJgZETL._SL500_.jpg",
        "bookLength": "25 hrs and 3 mins",
        "releaseDate": "24-10-11",
        "language": "English"
    },
    {
        "id": "f4008cdd-1c76-4071-8dab-830b6fd3c379",
        "name": "Gut",
        "author": "Giulia Enders",
        "narrated": "Katy Sobey",
        "img": "https://m.media-amazon.com/images/I/5110ffzUFkL._SL500_.jpg",
        "bookLength": "7 hrs and 26 mins",
        "releaseDate": "24-06-15",
        "language": "English"
    },
    {
        "id": "5a1caf9b-f7ce-4ada-9046-309c66b2dc36",
        "name": "The 4-Hour Work Week",
        "author": "Timothy Ferriss",
        "narrated": " Ray Porter",
        "img": "https://m.media-amazon.com/images/I/518+s5Nu4XL._SL500_.jpg",
        "bookLength": "13 hrs and 1 min",
        "releaseDate": "10-11-11",
        "language": "English"
    },
    {
        "id": "86084cd9-5191-4c7f-99b8-acbb930070f1",
        "name": "Cosmos",
        "author": "Carl Sagan",
        "narrated": "LeVar Burton, Seth MacFarlane, Neil deGrasse Tyson, Ann Druyan",
        "img": "https://m.media-amazon.com/images/I/51e91glnHUL._SL500_.jpg",
        "bookLength": "14 hrs and 31 mins",
        "releaseDate": "30-05-17",
        "language": "English"
    }
]

Модели/Книги.js.

const fs = require('fs');
const { v4: uuidv4 } = require('uuid');
const path = require('path');
const p = path.join(`${__dirname}/../data/books.json`);

const getBooksFromFile = (cb) => {
    fs.readFile(p, (err, fileContent) => {
        if (err) {
            cb([]);
        } else {
            cb(JSON.parse(fileContent));
        }
    });
};

module.exports = class Books {
    constructor(id, name, author, narrated, img, bookLength, releaseDate, language) {
        this.id = id;
        this.name = name;
        this.author = author;
        this.narrated = narrated;
        this.img = img;
        this.bookLength = bookLength;
        this.releaseDate = releaseDate;
        this.language = language;
    }
    save() {
        getBooksFromFile((books) => {
            this.id = String(uuidv4());

            books.push(this);

            fs.writeFile(p, JSON.stringify(books), (err) => {
                console.log(err);
            });
        });
    }
    static fetchAll(cb) {
        getBooksFromFile(cb);
    }
    static findById(id, cb) {
        getBooksFromFile((books) => {
            const bookId = books.find((b) => b.id === id);
            cb(bookId);
        });
    }
};

Маршруты/admin.js.

const express = require('express');
const router = express.Router();
const adminController = require('../controllers/admin');

router.get('/', adminController.getIndex);

router.get('/books', adminController.getBooks);

router.get('/books/:bookId', adminController.getBook);

router.post('/add-book', adminController.postAddBook);

module.exports = router;

Есть три грунтовых маршрута

http://localhost: 8080/Книги/ для отправки запроса на получение получения, которое вернет все книги как JSON

http://localhost: 8080/Книги/647F8D9A-97B5-461C-9CFE-B04D8B9E1028 Чтобы отправить запрос на получение, которое получит книгу по его bookId (просто замените идентификатор с одним из книг в файл, чтобы вернуть его данные как json)

http://localhost: 8080/Добавить-книга Для отправки запроса на почту, которое добавит новую книгу в файл. Это приложение не имеет формы, поэтому вам нужно будет использовать инструмент API, как бессонница или почтальон, чтобы добавить новые книги. Или вы могли бы просто сделать это вручную, обновляя файл в Данные/Книги.json.

И вот это для бэкэнда, который у вас сейчас есть динамические маршруты API, работающие на книжных данных.

Шаг 3: Настройка проекта Frontend

CD В корневую папку для вашего проекта, а затем скопируйте и вставьте этот код в свой терминал, а затем нажмите Enter, чтобы настроить свой проект React Frontend

mkdir frontend
cd frontend
npx create-react-app .
npm i react-router-dom

После завершения установки CD Вернитесь в папку Backend и запустите команду NPM запустить серверы Так что как серверы Backend, так и Frontend работают одновременно.

Перейти к папке Frontend и внутри SRC Создать папки для Компоненты и страницы Отказ Удалить все CSS внутри App.csss. Теперь мы собираемся получить React Router UP и запустив, поэтому сначала создайте файл под названием Home.js и положить его внутри страницы папка.

Обновите и добавьте код ниже в соответствующие файлы

Страницы/home.js.

import React, { Fragment } from 'react';

const Home = () => {
    return (
        
            

Book Library Home Page

); }; export default Home;

app.js.

import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Home from './pages/Home';
import './App.css';

const App = () => {
    return (
        
            
                
            
        
    );
};

export default App;

index.js.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(, document.getElementById('root'));

Теперь, когда вы идете в http://localhost: 3000/ Вы должны увидеть домашнюю страницу для книжной библиотеки

Шаг 4: Создайте приложение

Хорошо, давайте закончим строить это приложение!

Создайте компонент под названием Nav.js и положить его в Компоненты папка. Теперь создайте два файла Book.js. и Books.js и положить их в страницы папка.

Наконец скопируйте и замените код в файлы с кодом ниже

Компоненты/Nav.js.

import React, { Fragment } from 'react';
import { Link } from 'react-router-dom';

const Nav = () => {
    // Function for refreshing the page when the :bookId is put into the browser searchbar. Without it the Book component wont load unless you do a manual page reload.
    const refresh = () => {
        setTimeout(() => {
            window.location.reload();
        }, 100);
    };
    return (
        
            
        
    );
};

export default Nav;

Страницы/book.js.

import React, { Fragment, useEffect, useState } from 'react';
import Nav from '../components/Nav';

const Book = ({ match }) => {
    useEffect(() => {
        const getAPI = () => {
            const API = 'http://localhost:8080/books';

            fetch(API)
                .then((response) => {
                    return response.json();
                })
                .then((data) => {
                    console.log(data);
                    setLoading(true);
                    const book = data.find((p) => p.id === match.params.bookId);
                    setData(book);
                    console.log(book);
                });
        };
        getAPI();
    }, [match.params.bookId]);

    const [loading, setLoading] = useState(false);
    const [data, setData] = useState([]);

    return (
        
            

My Book

{loading === false ? (

Loading...

) : (
{data.name}

{data.name}

Author: {data.author}

Narrated by: {data.narrated}

Length: {data.bookLength}

Release Date: {data.releaseDate}

Language: {data.language}

{data.bookLength}

)}
); }; export default Book;

Страницы/Книги.js.

import React, { Fragment, useState, useEffect } from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import Nav from '../components/Nav';

const Books = () => {
    useEffect(() => {
        getAPI();
    }, []);

    const [loading, setLoading] = useState(false);
    const [data, setData] = useState([]);

    const getAPI = () => {
        const API = 'http://localhost:8080/books';

        fetch(API)
            .then((response) => {
                return response.json();
            })
            .then((data) => {
                console.log(data);
                setLoading(true);
                setData(data);
            });
    };

    // Function for refreshing the page when the :bookId is put into the browser searchbar. Without it the Book component wont load unless you do a manual page reload.
    const refresh = () => {
        setTimeout(() => {
            window.location.reload();
        }, 100);
    };

    return (
        
            
                

Library

Titles

{loading === false ? (

Loading...

) : (
{data.map((book) => (
{book.name}

{book.name}

Author: {book.author}

Narrated by: {book.narrated}

{book.bookLength}

))}
)}
); }; export default Books;

Страницы/home.js.

import React, { Fragment } from 'react';
import Nav from '../components/Nav';

const Home = () => {
    return (
        
            

SoundBite Original

The

Timeman

2 for 1

Choose from over 500 listens in top categories

Black Sunday

A journey to a new world leads to a revelation

Comedy House

Let the fun come to you in these specials

The Power

SoundBites best of the best by month

); }; export default Home;

App.csss.

@import url('https://fonts.googleapis.com/css2?family=Encode+Sans+Condensed:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Philosopher:ital,wght@1,700&display=swap');

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

html {
    font-size: 62.5%;
}

body {
    font-size: 1.6rem;
    font-family: 'Encode Sans Condensed', sans-serif;
    color: #333333;
}

main {
    max-width: 120rem;
    width: 100%;
    margin: 0 auto;
    padding: 2rem;
}

nav {
    display: flex;
    justify-content: start;
    margin-bottom: 4rem;
    align-items: flex-end;
}

nav a {
    margin-right: 2rem;
    text-decoration: none;
    color: #333333;
    font-weight: 500;
}

.logo {
    color: #333333;
    font-size: 3rem;
}

.logo::after {
    content: '';
    display: inline-block;
    width: 2rem;
    height: 2rem;
    background: #f2a517;
    border-radius: 100%;
    position: relative;
    top: -1rem;
}

.logo::before {
    content: 'a terraform company';
    display: block;
    width: 10rem;
    height: 2rem;
    position: relative;
    top: 5.5rem;
    left: 2rem;
    font-size: 1.2rem;
}

.hero {
    width: 100%;
    background: #333333;
    height: 40rem;
    text-align: center;
    color: #ffffff;
    padding: 5rem;
    display: grid;
    justify-content: center;
    align-items: center;
}

.hero h2,
.hero p {
    text-transform: uppercase;
    font-family: 'Philosopher', sans-serif;
}

.hero p {
    font-size: 9rem;
}

.hero button,
.banners button {
    background: #f1a517;
    border: none;
    border-radius: 0.5rem;
    padding: 1rem;
    cursor: pointer;
    margin: 1rem 0 1rem 0;
}

.banners {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    padding: 2rem;
    grid-gap: 2rem;
}

.banners section {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    background: #cccccc;
    padding: 4rem;
    grid-gap: 2rem;
}

.library-heading {
    border-bottom: 0.1rem solid rgb(236, 236, 236);
}

.library-heading h1 {
    font-size: 5rem;
}

.library-heading h2 {
    font-weight: 700;
    margin: 2rem 0 2rem 0;
}

.library-book {
    display: flex;
    flex-flow: row wrap;
    margin: 2rem 0 2rem 0;
    border-bottom: 0.1rem solid rgb(236, 236, 236);
}

.library-book img {
    width: 15rem;
    margin-right: 2rem;
    margin-bottom: 2rem;
}

.library-book-content {
    max-width: 80rem;
    width: 100%;
}

.library-book-content a {
    text-decoration: none;
}

.library-book-content h1 {
    font-size: 2rem;
    color: #333333;
    font-weight: 600;
}

.library-book-content p {
    margin: 1rem 0 1rem 0;
}

.library-book-listen {
    display: flex;
    flex-flow: column wrap;
    justify-content: space-evenly;
    margin: 2rem 0 2rem 0;
}

.btn-listen {
    background: #f1a517;
    border: none;
    border-radius: 0.5rem;
    padding: 1rem;
    cursor: pointer;
    margin: 1rem 0 1rem 0;
}

.btn-download {
    background: #e6e6e6;
    border: none;
    border-radius: 0.5rem;
    padding: 1rem;
    cursor: pointer;
    margin: 1rem 0 1rem 0;
}

@media screen and (max-width: 960px) {
    .banners {
        grid-template-columns: 1fr;
    }

    .library-book {
        justify-content: center;
        align-items: center;
    }
    .library-book-content {
        display: flex;
        flex-flow: column wrap;
        justify-content: center;
        align-items: center;
    }
}

App.js.

import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Home from './pages/Home';
import './App.css';
import Books from './pages/Books';
import Book from './pages/Book';

const App = () => {
    return (
        
            
                
                
                
            
        
    );
};

export default App;

Ваше приложение должно выглядеть как изображения ниже! Поздравляю, вы только что узнали основы создания маршрутов Backend и Frontend Dynamic API.

Книги Домашняя страница

Страница библиотеки книг

Моя книга страница

Оригинал: “https://dev.to/andrewbaisden/node-and-react-router-dynamic-api-routes-21mg”