Как стать автором
Обновить

Комментарии 50

Много кода и мало текста, люблю такие мануалы =)

Спасибо попробую как время будет, насколько я понимаю это замена DRF? Просто DRF пока не изучал, так немного пощупал.
Нет, ну точнее не совсем. FastAPI берёт некоторые идеи из DRF (ref), но предлагает другой подход — он более легковесен, и не вынуждает использовать какую-либо определенную структуру для проекта.

Мое ИМХО:


DRF это all-inclusive где с коробки есть почти всё что нужно для большинства сервисов.
Благодаря этому для него есть много плагинов, потому что автор плагина знает "ага раз DRF значить Django ORM, DRF Serializers/Views/etc."


С другой стороны есть Flask компоненты для которого нужно собирать словно кубики лего что требует траты много времени на исследованные всех "кубиков". Они к тому же очень часто не совместимы между собой.


А FastAPI это где то по середине. (ближе к Flask, но со некоторыми фишками)


Я бы пока брал DRF для продакшена.

А, подскажите, вот вы в качестве бд используете память, будет ли это вообще работать в продакшене? В WSGI — точно нет, так как у каждого процесса приложения своя память и состояние будет теряться. Как дела обстоят с ASGI?
Изначально ASGI (да и вся идея асинхронной модели) задумывался как однопроцессный сервер, следственно таких проблем быть не должно :) Но в продакшн можно запускать с помощью gunicorn+uvicorn-воркеры и тогда да, такая проблема появится)

Тоже проникся им где-то пол-года назад.
Боялся, что будут проблемы, потому что нет популярности, а значит и обмуждения в коммьюнити, но оказалось, что документация настолько хороша, что предугадывает практически все мои вопросы

Слова add и delete нарушают правила наименования restfull api. Стоит их убрать, что бы не вводить в заблуждение тех, кто будет пользоваться туториалом. У post и delete методов можно сделать /phrases или просто слеш.


То, что метод delete и так видно, дополнительное слово не нужно и не по стандарту.


Почему так, можно прочитать, например, тут.
https://restfulapi.net/resource-naming/

Это распространенный миф. Не существует никаких правил именования URI для REST. Все, что написано об именовании URI в этом мануале (и в других) является не больше, чем стилистической рекомендацией.


То, что метод delete и так видно, дополнительное слово не нужно и не по стандарту.

По какому стандарту?) Не бойтесь самостоятельно копнуть глубже, перед тем как открывать кому-то глаза.

По какому стандарту?)

Ну не стандарту, а стандартному стайл гайду. Это ничего не меняет.


Зачем писать:


POST /add
GET /get
DELETE /delete

вместо стандартного:


POST /
GET /
DELETE /

это то же самое что писать коментарии типа: n += 2 # add 2 to n — никакой новой информации

Но ведь никто не говорит, что такие комментарии нарушают, например, ООП.
Никакие глаголы в URI не нарушают REST. Вопрос стиля URI это ортогональный вопрос вкуса и внутренних соглашений.

Но ведь никто не говорит, что такие комментарии нарушают, например, ООП.

Вы правы, тип ошибки указана не верно. Но всё же она есть, согласны?


Вопрос стиля URI это ортогональный вопрос вкуса и внутренних соглашений.

Есть основной стиль, а есть "все другие".
Чем DELETE /delete лучше за DELETE /?

Чем DELETE /delete лучше за DELETE /?

Этот вопрос выходит за рамки REST. Я не хочу показаться ханжой, но поймите одну вещь. Зацикливаясь на необязательных ограничениях по стилистике URI, мы нарушаем одно из обязательных для REST — Uniform Interface, центральной частью которого является т. н. HATEOAS (https://restfulapi.net/hateoas/). Именно грубое нарушение этого ограничения не позволяет большинству API называться RESTful, вне зависимости от того, какой стиль URI используется.


Реализация HATEOAS в API сама по себе является полноценной работой, поэтому не удивительно, что очень мало кто так делает. Да и не всем это действительно нужно, если честно. Проблема лишь в том, что мы зациклены не на тех вещах.

Повторю вопрос:
В стандартном, указаном вами, гайде в разделе в разделе Never use CRUD function names in URIs предлагают делать DELETE /, но вы защищаете вариант с DELETE /delete


(пожалуйста не расширяйте фокус вопроса. можете даже проигнорировать то что сверху и ответить только на следующий вопрос)


Чем DELETE /delete лучше за DELETE /?

Коротко: Никоим образом не нарушая REST, он ничем не лучше.


Во-первых, я не защищаю никакой вариант URI. Во-вторых, вас точно не смущает слово "tips" по ссылке выше? В своем гайде по именованию автор отталкивается от собственных утверждений, не ссылаясь на первоисточники. Проблема всех таких гайдов в том, что они дают противоречивую информацию, не согласуясь даже друг с другом. Один запрещает использовать глаголы в URI; второй разрешает только те, которые нельзя выразить с помощью HTTP-методов, используя для этого свои понятия, которые отсутствуют в REST. Другие же честно разделяют обязательные и необязательные ограничения. Это порождает просто чудовищную путаницу в головах, превращая REST в хреновину, которую никто не может может толком описать.

вас точно не смущает слово "tips" по ссылке выше?

Нет.


Один запрещает использовать глаголы в URI; второй разрешает только те, которые нельзя выразить с помощью HTTP-методов, используя для этого свои понятия, которые отсутствуют в REST. Другие же честно разделяют обязательные и необязательные ограничения. Это порождает просто чудовищную путаницу в головах, превращая REST в хреновину, которую никто не может может толком описать.

Не согласен, но сейчас не об этом.


он ничем не лучше.

Я скажу чем хуже: +одно слово +0 информации (не я один такой умный, поэтому, это уже описали в этих "tips")
Вы согласны?

Согласен. Какое это имеет отношение к REST?

Лично я говорил только о DELETE /delete vs DELETE /.


И мы сошлисть на том, что пункт "Never use CRUD function names in URIs" оправдан. Можно пройтись и по другим пунктам.


Это всё что я хотел сказать.

https://developer.twitter.com/en/docs/api-reference-index.html
https://api.slack.com/methods
https://www.flickr.com/services/api/
https://vk.com/dev/methods
https://core.telegram.org/methods


Увы, не оправдан. Но перо скрипит, бумага терпит)


The problem is that various people have described “I am using HTTP” as some sort of style in itself and then used the REST moniker for branding (or excuses) even when they haven’t the slightest idea what it means. The only way to stop people from misusing the term is to make a negative example of them when they do.
https://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post#comment-996

Копнув немного глубже, вам больше не придется обсуждать это со мной)

Согласен с предыдущим коментарием, по смыслу REST ресурс это что-то что обознчается словом существительным, а не глаголом. Глаголы в REST используются стандартные от протокола HTTP.

Это очень узкая трактовка термина. Архитектура очень раннего веба (начало 1990 годов, еще до стандартизации HTTP/1.1) действительно определяла URI как идентификаторы документов, но такое определение оказалось неудовлетворительным и было отброшено. Любая адресуемая концепция вписывается в это понятие.
Чтобы не повторятся, можете прочитать https://habr.com/post/476576/#comment_20949240

Так и rest "не существует", если так рассуждать. Это просто правила, о которых люди договорились. К тому же не все, а некоторые. Вас же никто не заставляет их соблюдать. Но если вы хотите соблюдать и сделать именно rest api, тогда использовать delete или add неуместно.


И умерьте пафос, по возможности.

Чтобы долго не тошнить в комментариях, я задам несколько вопросов, а заодно кину несколько цитат от автора REST для дальнейших размышлений.


  • Что именно нарушают /add, /crop, /verify, /withdraw, глобальный /search в REST?
  • Как именно должны быть переименованы такие идентификаторы?
  • Кто именно создал такие требования?

A REST API must not define fixed resource names or hierarchies (an obvious coupling of client and server). Servers must have the freedom to control their own namespace. Instead, allow servers to instruct clients on how to construct appropriate URIs, such as is done in HTML forms and URI templates, by defining those instructions within media types and link relations.
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven


There is no such thing as a REST endpoint. There are resources. A countably infinite set of resources bound only by restrictions on URL length. A client can POST to a REST service to create a resource that is a GraphQL query, and then GET that resource with all benefits of REST [...]
https://twitter.com/fielding/status/1052976631374000128


At no time whatsoever do the server or client software need to know or understand the meaning of a URI — they merely act as a conduit through which the creator of a resource (a human naming authority) can associate representations with the semantics identified by the URI.
https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_2_4


REST accomplishes this by defining a resource to be the semantics of what the author intends to identify, rather than the value corresponding to those semantics at the time the reference is created.
https://www.ics.uci.edu/~fielding/pubs/dissertation/evaluation.htm#sec_6_2_1

/crop, /verify, /withdraw не нарушают ничего. В коротком документе, на который я дал ссылку, это описано, если вам интересно, прочитайте.


Цитаты — вода (что и не удивительно, диссертация же). Общий смысл — делайте так, как нужно для вашего приложения.


Что ж, соглашусь, если для вашего приложения действительно нужно два раза повторить слово delete и вы даже сможете это аргументировать, то пожалуйста. Если у вас таких аргументов нет, то на этом можно закончить.

Общий смысл — делайте так, как нужно для вашего приложения.

А когда-то было по другому?

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

Если конкретный архитектурный стиль вам не подходит — вы его не берёте. Но зачем пытаться сделать по другому, явно указывая что ограничения REST вам не нужны, и в то же время продолжать называть это REST, ещё и производя подмену понятий?

Просто фраза «делайте так, как нужно для вашего приложения» не может представлять собой архитектурный стиль.
Цитаты — вода (что и не удивительно, диссертация же).

Из приведённых выше цитат только две из диссертации, и даже их я бы водой не назвал. Просто вы вряд ли являетесь целевой аудиторией сего документа(и я тоже).
А для PHP есть такое же чудо?
Чем не устраивает lumen/laravel?
Да мне-бы только API…
Как и lumen — laravel без лишнего.
Спасибо за статью, вопрос такой:
А что с перфом?
не helloworld перфом, а с нормальной нагрузкой — доставать данные по сети, совершать обсчет каких-нибудь матриц ( не очень больших, но всё равно матриц)
Ходить за данными можно прекрасно, ибо асинхронный фреймворк, а вот считать матрицы придется в процесс-пулл экзекьюторе, чтобы эвент луп не заблокировать, но в wsgi с этим имхо еще хуже

Более подробные бенчмарки тык.
По поводу обсчёта матриц — если это нужно сделать в роуте который ничего асинхронно не делает, то можно маркнуть его как обычный def, а не async def, тогда FastAPI запустит его в тредпуле. А если всё таки хочется и сделать запрос с помощью aiohttp и посчитать что-то, то можно использовать такой код (WARNING: не тестировал, но уверен что работает):


from starlette.concurrency import run_in_threadpool

@app.get(...)
async def some(..):
    await do_async_request()
    result = await run_in_threadpool(compute_some(123))

Тут тоже всё не так однозначно: если нужно что-то посчитать, и числодробилка потенциально не высвобождает GIL, то всё равно выйдет блокирующая CPU-bound операция, и по-хорошему нужно либо вызвать loop.set_default_executor с инстансом ProcessPoolExecutor, либо спуститься на уровень ниже к loop.run_in_executor и делать ровно то же самое.
Конечно при условии, что это реально нужно, а не преждевременная оптимизация.

А как подключить к FastAPI базу с mysql?
Есть какой-нибудь рабочий образец?
С обычным sqlite работает норм:
main.py
from typing import List

import databases
import sqlalchemy
from fastapi import FastAPI
from pydantic import BaseModel

# SQLAlchemy specific code, as with any other app
DATABASE_URL = "sqlite:///./test.db"


database = databases.Database(DATABASE_URL)

metadata = sqlalchemy.MetaData()

notes = sqlalchemy.Table(
    "notes",
    metadata,
    sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
    sqlalchemy.Column("text", sqlalchemy.String),
    sqlalchemy.Column("completed", sqlalchemy.Boolean),
)


engine = sqlalchemy.create_engine(
    DATABASE_URL, connect_args={"check_same_thread": False}
)
metadata.create_all(engine)


class NoteIn(BaseModel):
    text: str
    completed: bool


class Note(BaseModel):
    id: int
    text: str
    completed: bool


app = FastAPI()


@app.on_event("startup")
async def startup():
    await database.connect()


@app.on_event("shutdown")
async def shutdown():
    await database.disconnect()


@app.get("/notes/", response_model=List[Note])
async def read_notes():
    query = notes.select()
    return await database.fetch_all(query)


@app.post("/notes/", response_model=Note)
async def create_note(note: NoteIn):
    query = notes.insert().values(text=note.text, completed=note.completed)
    last_record_id = await database.execute(query)
    return {**note.dict(), "id": last_record_id}



Подсовываю в
DATABASE_URL = "mysql://mydb:welcome@localhost/mydb"

И пишет, мол ModuleNotFoundError: No module named 'MySQLdb'
Спасибо за ответ. Это самое первое, что я сделал.
Так же сделал
pip install aiomysql


Как-то худо бедно заставил работать вот таким макаром:
pip install mysql-connector


DATABASE_URL = "mysql+mysqlconnector://mydb:welcome@localhost/mydb" 
Очень раздражают рекламные статьи, где рассказывают, как вместо зачем.

Вот мы видим очередной фреймворк (а то ж мы страдали, что мало фреймворков), и чо? Сильно ли оно поможет условному Васе Пупкину, developer-у, ускорить и обезглючить dev?

Для примера, доки на asyncio начинаются (ну надо же!!!) со слов: Why use asyncio?

И это правильно, товарищи. Условный Вася Пупкин, developer, для начала должен понять: why? Почему следует считать бесцельно прожитими все те годы, когда он не юзал фреймворк?

И уж только после этого начинать тратить годы жизни (если это можно назвать жизнью) на изучение этой ненужной фигни крайне полезной штуки.
еще радуют эти графики перфа, где показывают: смотри, наш фреймворк впереди планеты всей, он практически как JS, смотри: Триллиардище запросов в секунду. И график, где %framework_name%, о котором статья, всегда стоит на первом месте, а C идет типа за ним или перед ним))
и никто че-то не берется сравнить те фреймворки, которые на первых местах были еще в начале 2019-го года, ну странновато
Для построения своих REST API я использую связку Flask-RESTplus + Flask-Marshmallow.
Чем FastAPI может привлечь мое внимание на фоне указанных модулей?
Это не вопрос с кандибобером, мне действительно интересно, стоит ли переходить на использование FastAPI с вышеперечисленного?
Я тоже юзаю фляшку, но вот начал изучать FastAPI из-за его асинхронности и быстроты. Имхо, думаю, что будущее за ним. Правда столкнулся с граблями, которые пока не могу понять.
Вот даже задал вопрос на тостере:
qna.habr.com/q/692597
Ну дык, я для быстроты использую .Net Core. Там всё что надо присутствует.
То есть, концептуально, кроме «быстроты» ничего нового? Но я ведь правильно понимаю, что если надо что-то тяжелое достать или обработать, то можно использовать условный Celery и не париться?
Я делюсь с вами своими впечатлениями и мыслями:

1) Flask задумывался как микро фреймворк и лишь позже там появились модули отвечающие за restfull, и они ещё между собой спорят, кто лучше.
А fastapi уже на уровне архитектуры сразу rest.

2) Я согласен с вот этим комментом цитата:
Нафиг это фласк в 2019. Тогда уж лучше просто drf взять.
Есть aiomongo и aiohttp. Вот пример api на нем dev.to/apcelent/how-to-create-rest-api-using-aiohttp-54p1


3) Отличная документация у fastapi, читаешь как роман.

4) Очень понравилась работа с параметрами, которая идёт из коробки.

5) Никаких blueprint, которые дико бесят во фляшке. Разбивание на файлы, роуты и тд работает тоже из коробки.

Ну вот как-то так, но я пока с fastapi только разбираюсь и кое-что пишу на нем чисто для себя.
Дело не только в быстроте, асинхронное приложение более устойчиво к пиковым нагрузкам и равномерно распределяет нагрузку. Flask же работает через воркеры, их фиксированное число — столько приложение может обработать одновременных подключений, остальным придётся подождать в очереди.

Я же порекомендую связку aiohttp + jsonschema (для валидации схем в openapi) + iko (асинхронный аналог Marshmallow).

Замечу что асинхронный код писать сложнее, и нет устоявшихся решений для restapi.
Всем привет.

Если передаю в FastAPI текст типа:

«Trevoga sozdana
Aktivnaya Vyezd tehniki za pridely bazy
Duster»

, то получаю такую ошибку:

doc": "{\n \«secret_key\»: \"\",\n \«message_id\»: \«123123\»,\n \«message_text\»: \«Trevoga sozdana\nAktivnaya Vyezd tehniki za pridely bazy\nDuster\»\n}",

то есть он не хочет парсить строку, в которой есть \n (перенос строки).

Как это можно исправить?

Спасибо
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации