
Full disclaimer, I madeloafang
as a way to kill my time and is still in development.
The current implementation that we will be discussing is written in python. And the example shown will be in python 3.9.
So, let's begin.
What does it aim to solve.
Well, technically it's more about readability and being more verbose in terms of how the query is written and also removing the need to use an external library to send a request from the client's perspective. The way loafang achieves this is by making use of JSON syntax as it's one of those file types that is supported by a lot of languages out of the box.
And it's way too much fun to do something like this. So.....
A sample query
{"GET:get-user":{"user --name ad":["username","email"],"posts --user-id ad34":["latest"]}}
Let's talk about the parts of the query.
"GET:get-user":{"user --name ad":["username","email"],"posts --user-id ad34":["latest"]}
This is an execution block in terms of loafang terminology. You can have multiple execution blocks in the same loafang query (obviously)
GET:get-user
This is the block header, It specifies three things,
- A Request method, in this case, it's
GET
(The schema is case sensitive), - A unique id that represents the block. (get-user)
- A block property key. (It's optional)
These three things are arranged in the following order.METHOD:id:property-key
"user --name ad":["username","email"]
This is a query that needs to be executed from the server. And it has three parts.
- The head, here its user (this can be a database name or something like that).
- The args (
--name
) - contents, here
["username", "email"]
Now, the contents type must be a list forGET
andDELETE
queries.
And, must be a dict forPOST
,PUT
, andPATCH
, as these three methods require you to update or add things.
Let's write some code.
Let's make a simple example use case for loafang withfastapi
andtinydb
We will make a simple example where you canADD
,UPDATE
, andGET
data from the DB.
I won't let you remove your data from MY database.
Stuff we need
pip3 install loafang fastapi uvicorn tinydb
# app.pyfrom__future__importannotationsfromtypingimportAny,UnionfromargparseimportNamespace# type hinting purposes onlyfromfastapiimportFastAPI,HTTPExceptionfromloafangimportparse,Methods,MethodsError,QueryBuilderfromtinydbimportTinyDB,Query# what our query looks likequery=QueryBuilder("database")query.add_argument("uname",type=str)classRequestMethods(Methods):# class to handle/create a response for queries in a blockdef__init__(self)->None:# you can have different query parser for different request methodsself.get_query_parser=queryself.post_query_parser=queryself.put_query_parser=querydefget(self,args:Namespace,contents:list[str])->Any:# our database only has fields for name, username and email.ifnotall(iin["name","email"]foriincontents):raiseMethodsError(400,"Bad contents arguments")User=Query()db=TinyDB(args.database)db_ret=db.search(User.username==args.uname)ifnotdb_ret:raiseMethodsError(404,"User does not exists")else:user=db_ret[0]return{i:user[i]foriincontents}defpost(self,args:Namespace,contents:dict[str,Any])->Any:ifnotall(iincontentsforiin["name","email"]):raiseMethodsError(400,"Bad contents arguments")User=Query()db=TinyDB(args.database)ifdb.search(User.username==args.uname):raiseMethodsError(403,"User already exists")else:db.insert({"username":args.uname,**contents})return{"msg":f"user{args.uname} added."}defput(self,args:Namespace,contents:dict[str,Any])->Any:ifnotall(iincontentsforiin["name","email"]):raiseMethodsError(400,"Bad contents arguments")User=Query()db=TinyDB(args.database)user=db.search(User.username==args.uname)ifnotuser:raiseMethodsError(404,"User already exists")db.update(contents,User.username==args.uname)return{"msg":f"User updated successfully.{args.uname}"}request_methods=RequestMethods()# a vague representation of the loafang queryQueryType=Union[dict[str,Any],list[str]]# initialize the serverapp=FastAPI()@app.get("/")defread_root():return{"ping":"pong"}@app.post("/loaf")defloaf(data:QueryType):# the parsers gives you three things# The parsed data with all the output (None, if something goes wrong)# err code (only if something goes wrong, else None)# err message (only if something goes wrong else None)parsed_data,err,msg=parse(request_methods,data)returnparsed_dataifparsed_dataelseHTTPException(status_code=err,detail=msg)
Launch the server
uvicorn app:app
Now let's send a sample query to theloaf
endpoint and see what happens.
The query
{"GET:get-user:pe":{"db.json --uname adwaith":["name","email"]},"POST:add-user":{"db.json --uname adwaith":{"name":"ad","email":"adwaithrajesh3180@gmail.com"}},"PUT:update-user":{"db.json --uname adwaith | update-ad":{"name":"ad2","email":"new-email@example.com"},"after":"get-user"}}
The response
{"add-user":{"db.json --uname adwaith":{"msg":"user adwaith added."}},"update-user":{"update-ad":{"msg":"User updated successfully. adwaith"},"after":{"db.json --uname adwaith":{"name":"ad2","email":"new-email@example.com"}}}}
Let's analyze what the hell just happened here,
In the first execution block, you can see that there is ape
property key (currently that is the only one). It tells the parser to skip the block or "prevents the execution" of the block, the block can now be called from other blocks.
The second block is aPOST
block and has one query in it that adds a user with the name adwaith to the DB 'db.json'.
The third is aPUT
block that has one query that updates a user with the name adwaith. But there is something special with that block. It has anafter
key. It tells the parser that after it executes the current block it needs to execute the block specified in theafter
.
The
after
key can only point to a block that haspe
as its property key.
A block withpe
as its property cannot have anafter
key
You might also notice that there is a pipe|
in between the query. It specifies that anything after the pipe is an alias to the query. As you can see in the result, the key to a query's values is the query itself. So it might be hard at times to retrieve data using the query as the key.
So, that a brief intro toloafang
, feel free to ask questions, use the package and if you have any errors, pls report it or ask me ondiscord.
GitHub:https://github.com/Adwaith-Rajesh/loafang
Full Docs:https://adwaith-rajesh.github.io/loafang/
Have a nice day.
Happy Coding.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse