Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
corepost
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
nexlab
corepost
Commits
89864450
Commit
89864450
authored
Mar 02, 2012
by
Jacek Furmankiewicz
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
major change to enable custom routing to REST services from a single parent Resource
parent
39d43ed7
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
246 additions
and
88 deletions
+246
-88
__init__.py
corepost/__init__.py
+19
-0
routing.py
corepost/routing.py
+78
-43
arguments.py
corepost/test/arguments.py
+3
-3
filter_resource.py
corepost/test/filter_resource.py
+8
-7
home_resource.py
corepost/test/home_resource.py
+3
-5
multi_resource.py
corepost/test/multi_resource.py
+11
-16
rest_resource.py
corepost/test/rest_resource.py
+100
-0
utils.py
corepost/utils.py
+8
-0
web.py
corepost/web.py
+16
-14
No files found.
corepost/__init__.py
View file @
89864450
...
@@ -2,6 +2,25 @@
...
@@ -2,6 +2,25 @@
Common classes
Common classes
'''
'''
from
zope.interface
import
Interface
,
Attribute
#########################################################
#
# INTERFACES
#
#########################################################
class
IRestServiceContainer
(
Interface
):
"""An interface for all REST services that can be added within a root CorePost resource"""
services
=
Attribute
(
"All the REST services contained in this resource"
)
#########################################################
#
# CLASSES
#
#########################################################
class
Response
:
class
Response
:
"""
"""
Custom response object, can be returned instead of raw string response
Custom response object, can be returned instead of raw string response
...
...
corepost/routing.py
View file @
89864450
This diff is collapsed.
Click to expand it.
corepost/test/arguments.py
View file @
89864450
...
@@ -3,7 +3,7 @@ Argument extraction tests
...
@@ -3,7 +3,7 @@ Argument extraction tests
@author: jacekf
@author: jacekf
'''
'''
from
corepost.web
import
CorePost
,
validate
,
route
from
corepost.web
import
RestServiceContainer
,
validate
,
route
from
corepost.enums
import
Http
from
corepost.enums
import
Http
from
formencode
import
Schema
,
validators
from
formencode
import
Schema
,
validators
...
@@ -11,7 +11,7 @@ class TestSchema(Schema):
...
@@ -11,7 +11,7 @@ class TestSchema(Schema):
allow_extra_fields
=
True
allow_extra_fields
=
True
childId
=
validators
.
Regex
(
regex
=
"^jacekf|test$"
)
childId
=
validators
.
Regex
(
regex
=
"^jacekf|test$"
)
class
ArgumentApp
(
CorePost
):
class
ArgumentApp
():
@
route
(
"/int/<int:intarg>/float/<float:floatarg>/string/<stringarg>"
,
Http
.
GET
)
@
route
(
"/int/<int:intarg>/float/<float:floatarg>/string/<stringarg>"
,
Http
.
GET
)
def
test
(
self
,
request
,
intarg
,
floatarg
,
stringarg
,
**
kwargs
):
def
test
(
self
,
request
,
intarg
,
floatarg
,
stringarg
,
**
kwargs
):
...
@@ -29,5 +29,5 @@ class ArgumentApp(CorePost):
...
@@ -29,5 +29,5 @@ class ArgumentApp(CorePost):
return
"
%
s -
%
s -
%
s"
%
(
rootId
,
childId
,
kwargs
)
return
"
%
s -
%
s -
%
s"
%
(
rootId
,
childId
,
kwargs
)
def
run_app_arguments
():
def
run_app_arguments
():
app
=
ArgumentApp
(
)
app
=
RestServiceContainer
((
ArgumentApp
(),)
)
app
.
run
(
8082
)
app
.
run
(
8082
)
\ No newline at end of file
corepost/test/filter_resource.py
View file @
89864450
...
@@ -3,21 +3,21 @@ Server tests
...
@@ -3,21 +3,21 @@ Server tests
@author: jacekf
@author: jacekf
'''
'''
from
corepost.web
import
CorePost
,
route
from
corepost.web
import
RestServiceContainer
,
route
from
corepost.enums
import
Http
from
corepost.enums
import
Http
from
corepost.filters
import
IRequestFilter
,
IResponseFilter
from
corepost.filters
import
IRequestFilter
,
IResponseFilter
import
zope.interface
from
zope.interface
import
implements
class
AddCustomHeaderFilter
():
class
AddCustomHeaderFilter
():
"""Implements just a request filter"""
"""Implements just a request filter"""
zope
.
interface
.
implements
(
IRequestFilter
)
implements
(
IRequestFilter
)
def
filterRequest
(
self
,
request
):
def
filterRequest
(
self
,
request
):
request
.
received_headers
[
"Custom-Header"
]
=
"Custom Header Value"
request
.
received_headers
[
"Custom-Header"
]
=
"Custom Header Value"
class
Change404to503Filter
():
class
Change404to503Filter
():
"""Implements just a response filter that changes 404 to 503 statuses"""
"""Implements just a response filter that changes 404 to 503 statuses"""
zope
.
interface
.
implements
(
IResponseFilter
)
implements
(
IResponseFilter
)
def
filterResponse
(
self
,
request
,
response
):
def
filterResponse
(
self
,
request
,
response
):
if
response
.
code
==
404
:
if
response
.
code
==
404
:
...
@@ -25,7 +25,7 @@ class Change404to503Filter():
...
@@ -25,7 +25,7 @@ class Change404to503Filter():
class
WrapAroundFilter
():
class
WrapAroundFilter
():
"""Implements both types of filters in one class"""
"""Implements both types of filters in one class"""
zope
.
interface
.
implements
(
IRequestFilter
,
IResponseFilter
)
implements
(
IRequestFilter
,
IResponseFilter
)
def
filterRequest
(
self
,
request
):
def
filterRequest
(
self
,
request
):
request
.
received_headers
[
"X-Wrap-Input"
]
=
"Input"
request
.
received_headers
[
"X-Wrap-Input"
]
=
"Input"
...
@@ -33,14 +33,15 @@ class WrapAroundFilter():
...
@@ -33,14 +33,15 @@ class WrapAroundFilter():
def
filterResponse
(
self
,
request
,
response
):
def
filterResponse
(
self
,
request
,
response
):
response
.
headers
[
"X-Wrap-Output"
]
=
"Output"
response
.
headers
[
"X-Wrap-Output"
]
=
"Output"
class
FilterApp
(
CorePost
):
class
FilterService
():
path
=
"/"
@
route
(
"/"
,
Http
.
GET
)
@
route
(
"/"
,
Http
.
GET
)
def
root
(
self
,
request
,
**
kwargs
):
def
root
(
self
,
request
,
**
kwargs
):
return
request
.
received_headers
return
request
.
received_headers
def
run_filter_app
():
def
run_filter_app
():
app
=
FilterApp
(
filters
=
(
Change404to503Filter
(),
AddCustomHeaderFilter
(),
WrapAroundFilter
(),))
app
=
RestServiceContainer
(
services
=
(
FilterService
(),),
filters
=
(
Change404to503Filter
(),
AddCustomHeaderFilter
(),
WrapAroundFilter
(),))
app
.
run
(
8083
)
app
.
run
(
8083
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
...
...
corepost/test/home_resource.py
View file @
89864450
...
@@ -3,17 +3,15 @@ Server tests
...
@@ -3,17 +3,15 @@ Server tests
@author: jacekf
@author: jacekf
'''
'''
from
corepost.web
import
CorePost
,
route
from
corepost.web
import
RestServiceContainer
,
route
from
corepost.enums
import
Http
,
MediaType
,
HttpHeader
from
corepost.enums
import
Http
,
MediaType
,
HttpHeader
from
twisted.internet
import
defer
from
twisted.internet
import
defer
from
xml.etree
import
ElementTree
from
xml.etree
import
ElementTree
from
UserDict
import
UserDict
import
json
,
yaml
import
json
,
yaml
class
HomeApp
(
CorePost
):
class
HomeApp
():
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
CorePost
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
issue1
=
"issue 1"
self
.
issue1
=
"issue 1"
@
route
(
"/"
,
Http
.
GET
)
@
route
(
"/"
,
Http
.
GET
)
...
@@ -117,7 +115,7 @@ class HomeApp(CorePost):
...
@@ -117,7 +115,7 @@ class HomeApp(CorePost):
return
self
.
issue1
return
self
.
issue1
def
run_app_home
():
def
run_app_home
():
app
=
HomeApp
(
)
app
=
RestServiceContainer
((
HomeApp
(),)
)
app
.
run
()
app
.
run
()
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
...
...
corepost/test/multi_resource.py
View file @
89864450
'''
'''
A
CorePost module1 that can be merged into the main CorePost
Resource
A
RestServiceContainer module1 that can be merged into the main RestServiceContainer
Resource
'''
'''
from
corepost.web
import
CorePost
,
route
from
corepost.web
import
RestServiceContainer
,
route
from
corepost.enums
import
Http
from
corepost.enums
import
Http
from
twisted.web.resource
import
Resource
from
twisted.internet
import
reactor
from
twisted.web.server
import
Site
class
HomeApp
(
CorePost
):
class
HomeApp
():
@
route
(
"/"
)
@
route
(
"/"
)
def
home_root
(
self
,
request
,
**
kwargs
):
def
home_root
(
self
,
request
,
**
kwargs
):
return
"HOME
%
s"
%
kwargs
return
"HOME
%
s"
%
kwargs
class
Module1
(
CorePost
):
class
Module1
():
path
=
"/module1"
@
route
(
"/"
,
Http
.
GET
)
@
route
(
"/"
,
Http
.
GET
)
def
module1_get
(
self
,
request
,
**
kwargs
):
def
module1_get
(
self
,
request
,
**
kwargs
):
...
@@ -24,7 +22,8 @@ class Module1(CorePost):
...
@@ -24,7 +22,8 @@ class Module1(CorePost):
def
module1e_sub
(
self
,
request
,
**
kwargs
):
def
module1e_sub
(
self
,
request
,
**
kwargs
):
return
request
.
path
return
request
.
path
class
Module2
(
CorePost
):
class
Module2
():
path
=
"/module2"
@
route
(
"/"
,
Http
.
GET
)
@
route
(
"/"
,
Http
.
GET
)
def
module2_get
(
self
,
request
,
**
kwargs
):
def
module2_get
(
self
,
request
,
**
kwargs
):
...
@@ -35,12 +34,8 @@ class Module2(CorePost):
...
@@ -35,12 +34,8 @@ class Module2(CorePost):
return
request
.
path
return
request
.
path
def
run_app_multi
():
def
run_app_multi
():
app
=
Resource
()
app
=
RestServiceContainer
((
HomeApp
(),
Module1
(),
Module2
()))
app
.
putChild
(
''
,
HomeApp
())
app
.
run
(
8081
)
app
.
putChild
(
'module1'
,
Module1
())
app
.
putChild
(
'module2'
,
Module2
())
factory
=
Site
(
app
)
reactor
.
listenTCP
(
8081
,
factory
)
#@UndefinedVariable
reactor
.
run
()
#@UndefinedVariable
if
__name__
==
"__main__"
:
run_app_multi
()
\ No newline at end of file
corepost/test/rest_resource.py
0 → 100644
View file @
89864450
'''
Server tests
@author: jacekf
'''
from
corepost
import
Response
from
corepost.web
import
RestServiceContainer
class
DB
():
"""Fake in-memory DB for testing"""
customers
=
{}
class
Customer
():
"""Represents customer entity"""
def
__init__
(
self
,
customerId
,
firstName
,
lastName
):
(
self
.
customerId
,
self
.
firstName
,
self
.
lastName
)
=
(
customerId
,
firstName
,
lastName
)
self
.
addresses
=
{}
class
CustomerAddress
():
"""Represents customer address entity"""
def
__init__
(
self
,
customer
,
streetNumber
,
streetName
,
stateCode
,
countryCode
):
(
self
.
customer
,
self
.
streetNumber
,
self
.
streetName
.
self
.
stateCode
,
self
.
countryCode
)
=
(
customer
,
streetNumber
,
streetName
,
stateCode
,
countryCode
)
class
CustomerRestService
():
path
=
"/customer"
def
getAll
(
self
,
request
):
return
DB
.
customers
def
get
(
self
,
request
,
customerId
):
return
DB
.
customers
[
customerId
]
if
customerId
in
DB
.
customers
else
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
post
(
self
,
request
,
customerId
,
firstName
,
lastName
):
if
customerId
in
DB
.
customers
:
return
Response
(
409
,
"Customer
%
s already exists"
%
customerId
)
else
:
DB
.
customers
[
customerId
]
=
Customer
(
customerId
,
firstName
,
lastName
)
return
Response
(
201
)
def
put
(
self
,
request
,
customerId
,
firstName
,
lastName
):
if
customerId
in
DB
.
customers
:
DB
.
customers
[
customerId
]
.
firstName
=
firstName
DB
.
customers
[
customerId
]
.
lastName
=
lastName
return
Response
(
200
)
else
:
return
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
delete
(
self
,
request
,
customerId
):
if
customerId
in
DB
.
customers
:
del
(
DB
.
customers
[
customerId
])
return
Response
(
200
)
else
:
return
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
deleteAll
(
self
,
request
):
DB
.
customers
.
clear
()
return
Response
(
200
)
class
CustomerAddressRestService
():
path
=
"/customer/<customerId>/address"
def
getAll
(
self
,
request
,
customerId
):
return
DB
.
customers
def
get
(
self
,
request
,
customerId
):
return
DB
.
customers
[
customerId
]
if
customerId
in
DB
.
customers
else
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
post
(
self
,
request
,
customerId
,
firstName
,
lastName
):
if
customerId
in
DB
.
customers
:
return
Response
(
409
,
"Customer
%
s already exists"
%
customerId
)
else
:
DB
.
customers
[
customerId
]
=
Customer
(
customerId
,
firstName
,
lastName
)
return
Response
(
201
)
def
put
(
self
,
request
,
customerId
,
firstName
,
lastName
):
if
customerId
in
DB
.
customers
:
DB
.
customers
[
customerId
]
.
firstName
=
firstName
DB
.
customers
[
customerId
]
.
lastName
=
lastName
return
Response
(
200
)
else
:
return
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
delete
(
self
,
request
,
customerId
):
if
customerId
in
DB
.
customers
:
del
(
DB
.
customers
[
customerId
])
return
Response
(
200
)
else
:
return
Response
(
404
,
"Customer
%
s not found"
%
customerId
)
def
deleteAll
(
self
,
request
):
DB
.
customers
.
clear
()
return
Response
(
200
)
def
run_rest_app
():
app
=
RestServiceContainer
(
restServices
=
(
CustomerRestService
(),))
app
.
run
(
8085
)
if
__name__
==
"__main__"
:
run_rest_app
()
\ No newline at end of file
corepost/utils.py
View file @
89864450
...
@@ -22,3 +22,11 @@ def convertToJson(obj):
...
@@ -22,3 +22,11 @@ def convertToJson(obj):
return
json
.
dumps
(
obj
)
return
json
.
dumps
(
obj
)
except
Exception
as
ex
:
except
Exception
as
ex
:
raise
RuntimeError
(
str
(
ex
))
raise
RuntimeError
(
str
(
ex
))
def
checkExpectedInterfaces
(
objects
,
expectedInterface
):
"""Verifies that all the objects implement the expected interface"""
for
obj
in
objects
:
if
not
expectedInterface
.
providedBy
(
obj
):
raise
RuntimeError
(
"Object
%
s does not implement
%
s interface"
%
(
obj
,
expectedInterface
))
\ No newline at end of file
corepost/web.py
View file @
89864450
...
@@ -3,32 +3,35 @@ Main server classes
...
@@ -3,32 +3,35 @@ Main server classes
@author: jacekf
@author: jacekf
'''
'''
from
collections
import
defaultdict
from
corepost
import
Response
,
IRestServiceContainer
from
corepost
import
Response
from
corepost.enums
import
Http
from
corepost.enums
import
Http
,
HttpHeader
from
corepost.routing
import
UrlRouter
,
RequestRouter
from
corepost.utils
import
getMandatoryArgumentNames
,
convertToJson
from
corepost.routing
import
UrlRouter
,
CachedUrl
,
RequestRouter
from
enums
import
MediaType
from
enums
import
MediaType
from
formencode
import
FancyValidator
,
Invalid
from
formencode
import
FancyValidator
,
Invalid
from
twisted.internet
import
reactor
,
defer
from
twisted.internet
import
reactor
from
twisted.
web.http
import
parse_qs
from
twisted.
internet.defer
import
Deferred
from
twisted.web.resource
import
Resource
from
twisted.web.resource
import
Resource
from
twisted.web.server
import
Site
,
NOT_DONE_YET
from
twisted.web.server
import
Site
,
NOT_DONE_YET
import
re
,
copy
,
exceptions
,
json
,
yaml
from
zope.interface
import
implements
from
xml.etree
import
ElementTree
from
xml.etree.ElementTree
import
Element
#########################################################
from
twisted.internet.defer
import
Deferred
#
# CLASSES
#
#########################################################
class
CorePost
(
Resource
):
class
RestServiceContainer
(
Resource
):
'''
'''
Main resource responsible for routing REST requests to the implementing methods
Main resource responsible for routing REST requests to the implementing methods
'''
'''
isLeaf
=
True
isLeaf
=
True
implements
(
IRestServiceContainer
)
def
__init__
(
self
,
schema
=
None
,
filters
=
()):
def
__init__
(
self
,
s
ervices
=
(),
s
chema
=
None
,
filters
=
()):
'''
'''
Constructor
Constructor
'''
'''
self
.
services
=
services
self
.
__router
=
RequestRouter
(
self
,
schema
,
filters
)
self
.
__router
=
RequestRouter
(
self
,
schema
,
filters
)
Resource
.
__init__
(
self
)
Resource
.
__init__
(
self
)
...
@@ -83,7 +86,6 @@ class CorePost(Resource):
...
@@ -83,7 +86,6 @@ class CorePost(Resource):
reactor
.
listenTCP
(
port
,
factory
)
#@UndefinedVariable
reactor
.
listenTCP
(
port
,
factory
)
#@UndefinedVariable
reactor
.
run
()
#@UndefinedVariable
reactor
.
run
()
#@UndefinedVariable
##################################################################################################
##################################################################################################
#
#
# DECORATORS
# DECORATORS
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment