Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Storing object instances in the app context#8239

Discussion options

Description

In Flask, I've found this to be a common pattern to do something like this:

run_app.py

from api.factory import create_appapp = create_app()

api/factory.py

from flask import Flask, current_appimport redisimport configfrom api.resources.basic import basicdef create_app():    """Create the app."""    app = Flask(__name__)    app.config.from_object(config.ProductionConfig)    app.redis = redis.Redis(host=app.config["REDIS_HOST"], port=app.config["REDIS_PORT"])    app.register_blueprint(basic, url_prefix="/api/v1")

api/resources/basic.py

from flask import current_appfrom flask import Blueprintfrom webargs import fieldsfrom webargs.flaskparser import use_argsmod = Blueprint('basic', __name__)write_args = {"value": fields.Str(required=True)}@mod.route('/<str:key>', methods=['POST'])@use_args(write_args, key)def create_resource(args, key):   """POST resource to redis."""   current_app.redis.set(key, args["value"])   current_app.logger.info("inserted value into redis")   return {key: args["value"]}, 201@mod.route('/<str:key>', methods=['GET'])def retrieve_resource(key):   """GET value from redis."""   return {key: current_app.redis.get(key)}, 200

Is it possible to have a 'global' app context where you can put objects shared across request contexts, where you would access objects that you don't want to keep reinstantiating because it might be expensive and because of the convenience and how it makes it easier to reason about where 'objects' live. Likecurrent_app.redis, orcurrent_app.logger, orcurrent_app.kafka_producer. I read about Depends, and saw the examples provided for how to deal with dependencies / resources but I didn't see something like the above.

Might be a bad practice, but it's worked well for me so far.

You must be logged in to vote

Hi, I readed all of your suggestion and I want to show the way I was doing since I didn't see proposed in this discussion.

The goal is to have a global object that I can use for every request. And, at the same time, have type hints from the IDEs editors.

First I initialize those objects that are going to be shared by all request in my lifespan function and save them in the app.state property. For example, in this case a Redis db and templates of Jinja2.

@asynccontextmanagerasyncdeflifespan(app:FastAPI)->AsyncGenerator[dict[Any,Any],None]:app.state.templates=Jinja2Templates(TEMPLATES_DIR)app.state.redis=redis.Redis(host=REDIS_HOST,port=REDIS_PORT,db=0)try:   …

Replies: 18 comments 11 replies

Comment options

You should look at:https://fastapi.tiangolo.com/tutorial/sql-databases/ Ithink the db dependancy is what you describe:
On Fri, Mar 15, 2019 at 2:40 PM Lasse Vang Gravesen < ***@***.***> wrote: *Description* In Flask, I've found this to be a common pattern to do something like this: run_app.py from api.factory import create_app app = create_app() api/factory.py from flask import Flask, current_app import redis import config from webargs.flaskparser import use_args from api.resources.basic import basic def create_app(): """Create the app.""" app = Flask(__name__) app.config.from_object(config.ProductionConfig) app.redis = redis.Redis(host=app.config["REDIS_HOST"], port=app.config["REDIS_PORT"]) app.register_blueprint(basic, url_prefix="/api/v1") api/resources/basic.py from flask import current_app from flask import Blueprint from webargs import fields from webargs.flaskparser import use_args mod = Blueprint('basic', __name__) write_args = {"value": fields.Str(required=True)} @mod.route('/write/<str:key>', methods=['POST']) @use_args(write_args ) def create_resource(args, key): """POST resource to redis.""" current_app.redis.set(key, args["value"]) current_app.logger.info("inserted value into redis") return {key: args["value"]}, 201 @mod.route('/write/<str:key>', methods=['GET']) def retrieve_resource(key): """GET value from redis.""" return {key: current_app.redis.get(key)}, 200 Is it possible to have a 'global' app context where you can put objects shared across request contexts, where you would access objects that you don't want to keep reinstantiating because it might be expensive and because of the convenience and how it makes it easier to reason about where 'objects' live. Like current_app.redis, or current_app.logger, or current_app.kafka_producer. I read about Depends, and saw the examples provided for how to deal with dependencies / resources but I didn't see something like the above. Might be a bad practice, but it's worked well for me so far. — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <#81>, or mute the thread <https://github.com/notifications/unsubscribe-auth/ABDZPt4hbxMUXWPraZi2pTCysiKhBnXOks5vW6LUgaJpZM4b2fPB> .
You must be logged in to vote
0 replies
Comment options

@euri10
I read about that but I didn't think it was totally right and I didn't know how to adapt it to other resources while retaining the nice properties of the aforementioned approach.
Like for instance, if I were to create a Kafka producer for every single session that would be really inefficient, and it looks like the docs create a local sqlalchemy session at each request and then closes it.
So specifically, my issue with dependencies like suggested in the tutorial is that I didn't see a way to create an app-level instance of dependencies - where I want to avoid recreating the same instances over and over again on every request, and I also want to avoid having ephemereal resources that are initialized by a function call without really associating it with the app context.

The docs say:

request.state is a property of each Starlette Request object, it is there to store arbitrary objects attached to the request itself, like the database session in this case.

Where I would instead want anapp object where I can store arbitrary objects that can be accessed throughout the application, like you can choose to store objects in theapp object in Flask and then refer to those objects using thecurrent_app context.

If I can find out a nice way to do this using this or figure out a way to adapt dependencies such that they are immediately accessible from a common location.
I'm not sure if I like the thought-model that has you call a function to initialize something somewhere. I prefer initializing everything in a factory and then associate the created instances with the app itself as to make that globally available as needed by simply usingapp.state.db orapp.state.kafka_producer orapp.state.elasticsearch.

You must be logged in to vote
0 replies
Comment options

sorry I misunderstood youI may be wrong but I think for that you can use@app.on_event('startup') @app.on_event('shutdown')Le sam. 16 mars 2019 à 12:14 PM, Lasse Vang Gravesen <notifications@github.com> a écrit :
@euri10 <https://github.com/euri10> I read about that but I didn't think it was totally right and I didn't know how to adapt it to other resources while retaining the nice properties of the aforementioned approach. Like for instance, if I were to create a Kafka producer for every single session that would be really inefficient, and it looks like the docs create a local sqlalchemy session at each request and then closes it. So specifically, my issue with dependencies like suggested in the tutorial is that I didn't see a way to create an app-level instance of dependencies - where I want to avoid recreating the same instances over and over again on every request, and I also want to avoid having ephemereal resources that are initialized by a function call without really associating it with the app context. The docs say: request.state is a property of each Starlette Request object, it is there to store arbitrary objects attached to the request itself, like the database session in this case. Where I would instead want an app object where I can store arbitrary objects that can be accessed throughout the application, like you can choose to store objects in the app object in Flask and then refer to those objects using the current_app context. If I can find out a nice way to do this using this or figure out a way to adapt dependencies such that they are immediately accessible from a common location. I'm not sure if I like the thought-model that has you call a function to initialize something somewhere. I prefer initializing everything in a factory and then associate the created instances with the app itself as to make that globally available as needed by simply using app.state.db or app.state.kafka_producer or app.state.elasticsearch. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#81 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/ABDZPv5B-_KSJrFvCaJApV4Ez9KWgM8Gks5vXNIlgaJpZM4b2fPB> .
You must be logged in to vote
0 replies
Comment options

@euri10
I think I figured out how to approximately do something like this. Therequest object provides access to theapp object. If you assign variables to theapp objects you can later access it. See for instance this line in an example API that I quickly made.

https://github.com/Atheuz/Test-API/blob/master/api/routers/basic.py#L11

You must be logged in to vote
0 replies
Comment options

Hmm, in your case, why not a global object that you can import and use directly everywhere?

As you are not using something that requires transactions or something similar, just more or less atomic operations (Kafka, Redis), you can use the same object everywhere. You don't have to attach it to the app, just import it and use it.

Dependencies are for cases that need to somehow read data from the current request or similar things.

Adding things to the request state is for situations where you need to have something through all the request, like a SQLAlchemy session.

But in your case, if it's something that can be at the same application level, you don't really need to put it as a property in the application, you can just have the global object/variable in a file (module) and import it anywhere you need it. If you import it from different Python files, Python will take care of re-using the same object that was imported before.

Would that work for you?

You must be logged in to vote
0 replies
Comment options

@tiangolo

I've tried to keep global objects that I can import and use anywhere in other projects, but I've just found the experience of instantiating objects and attaching them as properties on the app context to be simpler to reason about and less confusing.

I think, my problem with the other approach, is a feeling that I don't know "when"/"if" global objects are instantiated, with the app context I handle instantiation through a factory where objects that I want to use are clearly instantiated and attached to the app context. If the app throws up an exception like:AttributeError: 'app' object has no attribute 'kafka_producer' - I know where to look for the problem, in the factory.py file where that instance SHOULD have been created but for some reason was not.
This also makes it simpler to test: Create an app in the conftest.py file, and then every functional object that the app requires is available through the app context without having to import 9 different functional objects. Also makes it simple to mock these properties out in cases I'm not interested in their behaviour, but rather if they get called as intended.

Examples of this in use:
Creating a logger for every single file in the application feels messy, whereas with this approach you would instantiate a logger once in the factory and assign it to the app as a property. Then the logger would be available through the app, like this:app.logger.info("I am a log entry", extra={"meaning-of-life": 42}).
This is what Flask does as well, where there is a logger object assigned to the app context that can be used anywhere in the application throughcurrent_app orapp.

Similarly with config, I like to have that be part of the application itself, so I can always refer to it anywhere through the app without having to think about if I should import it. For instance, if I define an hostname for an API that needs to be used multiple places in the application, I would like it to be available through the app context without having to import anything, like so:app.config["FIREBASE_API_URL"].
This is also what Flask does, also reachable throughapp orcurrent_app.

See here for an example of instantiation of a logger object:
https://github.com/Atheuz/Test-API/blob/master/api/factory.py

Then it's reused here, using therequest.app that's available:
https://github.com/Atheuz/Test-API/blob/master/api/routers/basic.py#L11

This almost works for me, except not everything in an API is necessarily an endpoint, for instance you can have actions or background tasks that you call from endpoints to perform some work, and in that case therequest instance is not available unless you pass it directly through from the callee. In Flask they resolve this by having it be possible to importcurrent_app, as a proxy forapp.

This is a pattern I've been using a lot over the last year and I don't know if I would want to change it without a good reason to.

You must be logged in to vote
0 replies
Comment options

I extended the pattern in my example API a little bit:

https://github.com/Atheuz/Test-API/blob/master/api/actions/storage.py#L14

Seems to be alright like this.
I'll also look into putting the objects into modules and then importing them at some point.

You must be logged in to vote
0 replies
Comment options

Cool! I'm glad you found a way to solve your problem that matches well your workflow.

You must be logged in to vote
0 replies
Comment options

@tiangolo still not totally sure about this approach. I'd like a standard way to do it. In Flask, apparently the current_app object is magic and handles locking per session that's using it so you don't end up in bad situations. The above mentioned approach would work in instances where the object to be used is atomic and/or thread safe. So I think for Kafka and Redis it might be OK. I doubt that it's OK with SQLAlchemy and I need to do something like the dependency injection to establish a local session.

You must be logged in to vote
0 replies
Comment options

For SQLAlchemy you probably want to attach the session to the request (that's what SQLAlchemy recommends), as in the docs:https://fastapi.tiangolo.com/tutorial/sql-databases/

You must be logged in to vote
0 replies
Comment options

@tiangolo, I'm working with a colleague on a FastAPI application and we're having a discussion about the merits of global module variables vs. passed dependencies. I've been advocating dependency passing as a way to modularize an application, govern access, facilitate testing, etc. For example, I've been advocating that a database repository object should be passed as a dependency of some kind and should not be a globally accessible module variable.

We noticed this issue and your comment about globals on 2019/3/17. I'm hoping you'll weigh in again since we're looking to the broader Python community for guidance on this question. Are global module variables considered idiomatic Python? Are the pitfalls of globals less applicable here? Can you think of FastAPI reference applications that heavily use module globals as a way to distribute dependencies like caches, database repositories, etc?

You must be logged in to vote
1 reply
@manuelinfosec
Comment options

I've had similar concerns. In my case, I made a pool globally available from theapp.state.pool attribute and acquire a connection from the pool in theget_db dependency. Would you consider this an overkill?

Comment options

@ebarlas you're 100% right. The way FastAPI documentation proposing app configuration assuming you have global variables for use with (angular-style inspired)? dependency injection, and in big projects it will be a huge mess, but MORE important - it's complex to write reusable modules for different apps.
Other frameworks trying to solve this in different way, happily FastAPI is based on starlette - and there isrequest.state and request.app.state variables.Pseudo-code for proper application configuration will look something like this, use this factory in tests to override settings without ugly hacks like documentation suggests.

create_app(**config):  config.set_default('debug', true)  config.set_default('db_url', 'sqlite://:memory:')  app = FastAPI(app)  app.state.config = config  setup_database(app)  # reads app.state.config, register middleware for request.state.db_session  setup_redis(app)  # something similar  return app
You must be logged in to vote
0 replies
Comment options

I am experiencing troubles with this, what do you think of my implementation

@MchlUh you are commenting on a closed issue and I do not see 1) what your problem is and 2) how the snipped relates to global state. I suggest you create a new question issue and provide a minimal working example.

You must be logged in to vote
0 replies
Comment options

I am experiencing troubles with this, what do you think of my implementation

@MchlUh you are commenting on a closed issue and I do not see 1) what your problem is and 2) how the snipped relates to global state. I suggest you create a new question issue and provide a minimal working example.

Thanks, I'll follow your advice

You must be logged in to vote
0 replies
Comment options

I would not use the app or request state as that can't be properly typed, so tooling like editors and mypy won't be able to help you make sure that you're not making bugs detectable by those tools, giving you certainty that your app is bug free, at least from type errors. You would also not get autocompletion in your editor.

If I needed to have something that works like a global but that I would be able to change, for example in tests, I would use a function that returns the value, and I would put anlru_cache to make sure it returns the same thing always. Like in the docs for settings:https://fastapi.tiangolo.com/advanced/settings/#creating-the-settings-only-once-with-lru_cache

Sorry for the long delay! 🙈 I wanted to personally address each issue/PR and they piled up through time, but now I'm checking each one in order.

You must be logged in to vote
0 replies
Comment options

Just wanted to follow up here and explain a situation where using Globals is not the right approach vs using app level state@tiangolo.

If you wanted a long running aiohttp session, you might just create it globally. However there is a weirdness in aiohttp that does not allow you to use the timeout parameter if youdont create the session inside of an async task. And so what would be the option here? Seems like the only way to do that is to create the session on app start and attach it to the app state no? The use case here is you don't want to open a new session for every app-request, as a single session per app is preferred in some scenarios.

You must be logged in to vote
0 replies
Comment options

I've had a good read through the thread and this is also something my company are debating internally at the moment. The main themes seem to be:

  1. Typing and IntelliSense Support
  2. Clarity and Control Over Resource Instantiation
  3. Simplicity and Ease of Use
  4. Consistency and Singleton Assurance

I would like to suggest a resource manager.

# resources.pyimportloggingfromsqlalchemy.engine.baseimportEnginefromsqlalchemyimportcreate_engineclassResourceManager:def__init__(self):self._logger=Noneself._db_engine=Noneself.get_logger()self.get_db_engine()defget_logger(self)->logging.Logger:ifnotself._logger:self._logger=logging.getLogger("my_logger")# Configure the loggerreturnself._loggerdefget_db_engine(self)->Engine:ifnotself._db_engine:# Setup database engineself._db_engine=create_engine("sqlite:///mydatabase.db")returnself._db_engine# Create a global instance of ResourceManagerresource_manager=ResourceManager()
# some_other_module.pyfromresourcesimportresource_managerdb_engine=resource_manager.get_db_engine()logger=resource_manager.get_logger()

Advantages are:

  • Easy and clear to understand how global resources are instantiated
  • Specifying method return types provides your IDE with the information it needs to provide auto-completion
  • Can be imported from any module easily
  • Confidence that only one instance of a resource has been instantiated
  • Resources are created before the app begins serving requests

This solution is very similar to the onetiangolo suggested for get_settings() where he uses lru_cache but perhaps this version provides the clarity that people seem to be wanting?

You must be logged in to vote
5 replies
@RyanCodrai
Comment options

I updated the ResourceManager.init() to instantiate its resources. This ensures the resources will be created before the app is ready to serve requests.

I tested this along with a method with the @app.on_event("startup") decorator. I put a 5 second syncronous time.sleep blocking call in the startup function and the same in one of the resources.

[ryancodrai:~/git/api_resources_test]$ python3 -m uvicorn main:app --reloadINFO:     Will watch for changes in these directories: ['/Users/ryancodrai/git/api_resources_test']INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)INFO:     Started reloader process [71069] using StatReloadstarted creation of resourcefinished creation of resourceINFO:     Started server process [71071]INFO:     Waiting for application startup.start of startup eventend of startup eventINFO:     Application startup complete.INFO:     127.0.0.1:58422 - "GET /test HTTP/1.1" 200 OK

The resources are created before the startup event is called.@tiangolo have I missed something? What are the advantages of using lifespan events over this resource manager? Thank you.

@ruben-vb
Comment options

I like that solution. I'm using it slightly modified with the@property decorator though, so like this:

# resources.pyimportloggingfromsqlalchemy.engine.baseimportEnginefromsqlalchemyimportcreate_engineclassResourceManager:def__init__(self):self._logger=Noneself._db_engine=None@propertydeflogger(self):ifnotself._logger:self._logger=logging.getLogger("my_logger")# Configure the loggerreturnself._logger@propertydefdb_engine(self):ifnotself._db_engine:# Setup database engineself._db_engine=create_engine("sqlite:///mydatabase.db")returnself._db_engine# Create a global instance of ResourceManagerresource_manager=ResourceManager()

I find that to be a little more pythonic. Or is there any downside to this over the getter/setter thing in this context?

@RyanCodrai
Comment options

I think both versions are pythonic. I can see two issues with your code. 1. You're not instantiating your resources. 2. You're not providing return types so that your IDE can do autocomplete.

Here's some updated code that you might find useful.

importinspectimportloggingfromcachetoolsimportLRUCache,cached,keysfromsqlalchemyimportcreate_enginefromsqlalchemy.engine.baseimportEnginedefcached_resource(maxsize:int=1):returncached(cache=LRUCache(maxsize=maxsize),key=keys.methodkey,    )classResourceManager:def__init__(self):self.logger()self.db_engine()@property@cached_resource()deflogger(self)->logging.Logger:returnlogging.getLogger("my_logger")@property@cached_resource()defdb_engine(self)->Engine:returncreate_engine("sqlite:///mydatabase.db")# Create a global instance of ResourceManagerresource_manager=ResourceManager()
@ruben-vb
Comment options

Ah yeah, I thought I wouldn't need to do that since it was only gonna happen once when they are first called and in my case that happens implicit at startup, but explicit is better. I'm gonna stick with your initial version then, it looks cleaner :D

For the LRU cache: What's the benefit of that? I thought if the property got called once it's essentially set and would then work just like a getter. I'm not that experienced with python in actual applications, thanks for your help :)

@RyanCodrai
Comment options

I like my 2nd version because the resource creation functions don't need to cache themselves in the instance but you are of course welcome to use whichever code you like best. If you would like to understand these more I think if you copy and paste both versions into ChatGPT or Claude and interogate the code it will be able to give you good explanations as to what the differences are. It will also be able to answer any follow up questions.

Comment options

Hi, I readed all of your suggestion and I want to show the way I was doing since I didn't see proposed in this discussion.

The goal is to have a global object that I can use for every request. And, at the same time, have type hints from the IDEs editors.

First I initialize those objects that are going to be shared by all request in my lifespan function and save them in the app.state property. For example, in this case a Redis db and templates of Jinja2.

@asynccontextmanagerasyncdeflifespan(app:FastAPI)->AsyncGenerator[dict[Any,Any],None]:app.state.templates=Jinja2Templates(TEMPLATES_DIR)app.state.redis=redis.Redis(host=REDIS_HOST,port=REDIS_PORT,db=0)try:yield {}finally:awaitapp.state.redis.aclose()

Then I create a dependency which return the object needed:

fromtypingimportTYPE_CHECKING,AnnotatedfromfastapiimportDepends,RequestifTYPE_CHECKING:fromfastapi.templatingimportJinja2Templatesdefget_templates(request:Request):returnrequest.app.state.templatesTemplatesDep=Annotated[Jinja2Templates,Depends(get_templates)]

And use in my route handler like this:

@router.get("/")asyncdefindex(request:Request,templates:TemplatesDep):returntemplates.TemplateResponse(request=request,name="index.html",context={})

What do you think about this way guys? 🤓

You must be logged in to vote
5 replies
@RyanCodrai
Comment options

I personally don't like your solution because it attaches resources to app.state which is then never accessed directly and therefore unnecessary - after all you use get_templates to retrieve the templates. Advantages that your code does have is the cleanup of resources and that this can be done asynchronously.

If we combine our code we get quite a nice implementation in my opinion.

importloggingfromsqlalchemyimportcreate_enginefromsqlalchemy.engine.baseimportEngineclassResourceManager:def__init__(self)->None:self.resources= {}def__setitem__(self,key,resource):self.resources[key]=resource@propertydeflogger(self)->logging.Logger:returnself.resources.get('logger')@propertydefdb_engine(self)->Engine:returnself.resources.get("db_engine")resource_manager=ResourceManager()@asynccontextmanagerasyncdeflifespan(app:FastAPI)->AsyncGenerator[dict[Any,Any],None]:resource_manager["logger"]=logging.getLogger("my_logger")resource_manager["db_engine"]=create_engine("sqlite:///mydatabase.db")yieldawaitresource_manager.db_engine.close_connection()

NOTE: Code is not runnable and tested. I'm just trying to illustrate a design pattern.

@jcamatta
Comment options

Yep, I was thinking the same.

I got the feelling that was a little unnecessary to attach to app.state. You may think, what is the difference against the solution of tiangolo. Well, in some cases there are resources that take a looong time to create and maybe you dont want to make the latency of the first request take too long because of that, since the first request will trigger the first dependency injection.

I really like your solution. I am going to use it for sure. I think it has the best of both worlds!

@RyanCodrai
Comment options

It's important to be able to run some resources with await because grabbing the event loop can create errors where futures are attached to the wrong loop. It's much better to make the call from inside the correct event loop from the start. And, like you said, it's important to not serve requests before the resources are initialised otherwise you will receive errors.

@RyanCodrai
Comment options

importloggingfromabcimportABC,abstractmethodfromcontextlibimportasynccontextmanagerfromtypingimportTypefromfastapiimportFastAPIclassResource(ABC):@abstractmethodasyncdefinit(self):# Initalise and return the resource        ...@abstractmethodasyncdefcleanup(self,resource):# The resource param is the resource returned by self.init()        ...classLogger(Resource):asyncdefinit(self):returnlogging.getLogger("my_logger")asyncdefcleanup(self,resource):passclassResources:def__init__(self,resources:list[Resource])->None:self.resources:dict[Type[Resource],Resource]= {resource:resource()forresourceinresources        }self.initialised_resources= {}asyncdefinit(self):forresource_class,resourceinself.resources.items():self.initialised_resources[resource_class]=awaitresource.init()asyncdefcleanup(self):forresource_class,resourceinself.resources.items():awaitresource.cleanup(self.initialised_resources[resource_class])@propertydeflogger(self)->logging.Logger:returnself.initialised_resources.get(Logger)resources=Resources([Logger])@asynccontextmanagerasyncdeflifespan(app:FastAPI):try:awaitresources.init()yieldfinally:awaitresources.cleanup()
@jcamatta
Comment options

Maybe instead of making the keyType[Resource] you may want to use some string defined in a constant.py file.
There are cases where you init the same resource (or class) but with a different set of arguments.

Answer selected byYuriiMotov
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Labels
questionQuestion or problemquestion-migrate
12 participants
@LasseGravesen@ebarlas@euri10@tiangolo@vgavro@chbndrhnns@RyanCodrai@lucasgadams@ruben-vb@MchlUh@manuelinfosec@jcamatta
Converted from issue

This discussion was converted from issue #81 on February 28, 2023 14:57.


[8]ページ先頭

©2009-2025 Movatter.jp